我正在使用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
}
还有其他更简单的方法吗?
答案 0 :(得分:1)
注意:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。
我正在尝试为您提供一个不错的解决方法,但下面是一个增强请求,您可以按照我们要增强的@XmlCDATA
注释来使这个用例更容易支持。< / p>
更新#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库的方法,利用XmlAdapter
和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
的方式。请注意,这会覆盖此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>