2

私はEclipseLink JAXB (MOXy)を使用しています。Java クラスのプロパティが CDATA であるか動的ではないという問題があります。例えば、

class Embed{  
//@XmlValue only  
//OR @XmlValue @CDATA  
private String value; //THIS CAN BE CDATA OR NOT  
}

私は、あるサブクラスが単なる値としてプロパティを持ち、別のサブクラスが CDATA としてプロパティを持つ継承を使用して問題を解決しようとしました。このソリューションで私が抱えている問題は、生成された Xml に xsi:type と xmlns:xsi の情報が含まれていることです。これは、レガシー コードをアップグレードしていて、生成された xml がレガシー コードとまったく同じである必要があるためです。

私が試した解決策:

@XmlAccessorType(XmlAccessType.FIELD)  
@XmlType(name = "itemType", namespace = "", propOrder = {"embed"}  
public class Item{  
 List`<Embed>` embed;  
 //getter and setters  
}

@XmlAccessorType(XmlAccessType.NONE)  
@XmlSeeAlso(EmbedDefault.class, EmbedAsCdata.class)  
public abstract class Embed{

}

@XmlAccessorType(XmlAccessType.FIELD)    
@XmlType( propOrder = {"value"})  
public class EmbedDefault extends Embed{

@XmlValue
protected String value;
 //getters and setters  
}

@XmlAccessorType(XmlAccessType.FIELD)  
@XmlType(propOrder = {"value"})  
public class EmbedAsCdata extends Embed {  

@XmlValue
@XmlCDATA
protected String value;
//getters and setters  
}

そのような別の簡単なアプローチはありますか?

4

1 に答える 1

1

注: 私はEclipseLink JAXB (MOXy)のリーダーであり、JAXB (JSR-222)エキスパート グループのメンバーです。

私は適切な回避策を考え出そうとしていますが、以下は、@XmlCDATAこのユースケースをより簡単にサポートできるようにするためにアノテーションを拡張するための拡張リクエストです。


更新 #1

以下は、私があなたのユースケースに取り組んでいるアプローチです。MOXy を少し変更する必要があることはわかっていますが、まだ完全にテストする必要があります。次のリンクを使用して、この問題の進行状況を追跡できます。

DomHandler (CdataHandler)

JAXB にはDomHandler、XML の外観をさらに制御できる の概念があります。必要に応じて、を活用してブロックDomHandlerを追加します。CDATA

package forum14145131;

import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.DomHandler;
import javax.xml.parsers.*;
import javax.xml.transform.Source;
import javax.xml.transform.dom.*;

import org.w3c.dom.*;

public class CdataHandler implements DomHandler<String, DOMResult> {

    private static DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();;

    @Override
    public DOMResult createUnmarshaller(ValidationEventHandler veh) {
        return new DOMResult();
    }

    @Override
    public String getElement(DOMResult domResult) {
        Document document = (Document) domResult.getNode();
        return document.getDocumentElement().getTextContent();
    }

    @Override
    public Source marshal(String string, ValidationEventHandler veh) {
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document document = db.newDocument();

            Node node;
            if(string.contains("<") || string.contains("&") || string.contains("&")) {
                node = document.createCDATASection(string);
            } else {
                node = document.createTextNode(string);
            }
            return new DOMSource(node);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

}

埋め込む

@XmlAnyElement注釈は、を指定するために使用されますDomHandler

package forum14145131;

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
class Embed{  

    @XmlAnyElement(CdataHandler.class)
    private String value; //THIS CAN BE CDATA OR NOT  

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}

詳細については


更新 #2

XmlAdapter以下は、および を利用する既存の EclipseLink ライブラリを使用して、現在使用できるアプローチですCharacterEscapeHandler

XmlAdapter (CdataAdapter)

package forum14145131;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class CdataAdapter extends XmlAdapter<String, String> {

    @Override
    public String marshal(String string) throws Exception {
        if(string.contains("&") || string.contains("<") || string.contains("\"")) {
            return "<![CDATA[" + string + "]]>";
        } else {
            return string;
        }
    }
    @Override
    public String unmarshal(String string) throws Exception {
        return string;
    }

}

埋め込む

@XmlJavaTypeAdapter注釈は、を指定するために使用されますXmlAdapter

package forum14145131;

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
class Embed{  

    @XmlValue
    @XmlJavaTypeAdapter(CdataAdapter.class)
    private String value; //THIS CAN BE CDATA OR NOT  

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}

デモ

を指定する方法は次のとおりですCharacterEscapeHandler。これは、 this のすべての文字エスケープをオーバーライドすることに注意してくださいMarshaller。これは、そのCDATA部分がエスケープされないようにするためです。製品コードの場合、このメソッドの実装は、この例で示されているものより強化する必要があります。

package forum14145131;

import java.io.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.oxm.CharacterEscapeHandler;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Embed.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum14145131/input.xml");
        Embed embed = (Embed) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.setProperty(MarshallerProperties.CHARACTER_ESCAPE_HANDLER,
                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(embed, System.out);
    }

}

input.xml/出力

<?xml version="1.0" encoding="UTF-8"?>
<embed><![CDATA[Hello & World]]></embed>
于 2013-01-05T11:51:45.867 に答える