2013-01-03 66 views
2

我正在使用EclipseLink JAXB (MOXy)。我有一個Java類的屬性可以是CDATA或不動態的問題。例如,使用MOXy的JAXB中的動態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 
} 

是否有這樣的另一個更簡單的方法?

回答

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

下面是一個辦法,你Ç一個使用今天使用現有的EclipseLink庫利用的XmlAdapterCharacterEscapeHandler

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。注意這將覆蓋此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> 
+0

感謝您的答覆。可能你已經考慮過了,但考慮到上述問題,建議的增強解決方案仍然存在相同的問題。即使我們設置了@XmlCDATA(XmlCDATAType.Optional),如果值是CDATA,問題(如何動態識別)仍然存在。或者,在使用@XmlCDATA(XmlCDATAType.Optional)時,如何決定是否渲染CDATA,您有任何想法。再次感謝。 – user1946448

+0

@ user1946448 - 沒問題。我用另一種方法更新了我的答案,但是它需要對MOXY進行一些小改動,我仍然需要進行全面測試。爲了確定CDATA塊的存在,我只是要檢查是否存在'',''''或''',這對您的用例足夠了嗎? –

+0

我衷心感謝您的更新。 #2,CharacterEscapeHandler不會逃避所有角色,也可能是你說它需要「加強」的原因。你認爲這並不是逃避所有角色的問題嗎?如果是這樣,我們可以使用一些默認轉義模式並修改它以排除cdata – user1946448