Shr*_*ang 40 java xml jaxb cdata
我正在使用JAXB将我的数据序列化为XML.类代码很简单,如下所示.我想生成包含CDATA块的XML,用于某些Args的值.例如,当前代码生成此XML:
<command>
<args>
<arg name="test_id">1234</arg>
<arg name="source"><html>EMAIL</html></arg>
</args>
</command>
Run Code Online (Sandbox Code Playgroud)
我想在CDATA中包装"source"arg,使其如下所示:
<command>
<args>
<arg name="test_id">1234</arg>
<arg name="source"><[![CDATA[<html>EMAIL</html>]]></arg>
</args>
</command>
Run Code Online (Sandbox Code Playgroud)
我怎样才能在下面的代码中实现这一点?
@XmlRootElement(name="command")
public class Command {
@XmlElementWrapper(name="args")
protected List<Arg> arg;
}
@XmlRootElement(name="arg")
public class Arg {
@XmlAttribute
public String name;
@XmlValue
public String value;
public Arg() {};
static Arg make(final String name, final String value) {
Arg a = new Arg();
a.name=name; a.value=value;
return a; }
}
Run Code Online (Sandbox Code Playgroud)
bdo*_*han 28
注意: 我是EclipseLink JAXB(MOXy)的负责人,也是JAXB(JSR-222)专家组的成员.
如果您使用MOXy作为JAXB提供程序,那么您可以利用@XmlCDATA扩展:
package blog.cdata;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlCDATA;
@XmlRootElement(name="c")
public class Customer {
private String bio;
@XmlCDATA
public void setBio(String bio) {
this.bio = bio;
}
public String getBio() {
return bio;
}
}
Run Code Online (Sandbox Code Playgroud)
欲获得更多信息
a2n*_*ade 20
使用JAXB Marshaller#marshal(ContentHandler)编组成一个ContentHandler对象.只需覆盖characters您正在使用的ContentHandler实现的方法(例如JDOM SAXHandler,Apache XMLSerializer等):
public class CDataContentHandler extends (SAXHandler|XMLSerializer|Other...) {
// 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();
}
}
Run Code Online (Sandbox Code Playgroud)
这比使用该方法要好得多,XMLSerializer.setCDataElements(...)因为您不必对任何元素列表进行硬编码.只有在需要时才会自动输出CDATA块.
小智 16
解决方案评论
我使用XMLStreamWriter实现修改了a2ndrade的解决方案.此解决方案非常有效.
XMLOutputFactory xof = XMLOutputFactory.newInstance();
XMLStreamWriter streamWriter = xof.createXMLStreamWriter( System.out );
CDataXMLStreamWriter cdataStreamWriter = new CDataXMLStreamWriter( streamWriter );
marshaller.marshal( jaxbElement, cdataStreamWriter );
cdataStreamWriter.flush();
cdataStreamWriter.close();
Run Code Online (Sandbox Code Playgroud)
那就是CDataXMLStreamWriter实现.委托类简单地将所有方法调用委托给给定的XMLStreamWriter实现.
import java.util.regex.Pattern;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
/**
* Implementation which is able to decide to use a CDATA section for a string.
*/
public class CDataXMLStreamWriter extends DelegatingXMLStreamWriter
{
private static final Pattern XML_CHARS = Pattern.compile( "[&<>]" );
public CDataXMLStreamWriter( XMLStreamWriter del )
{
super( del );
}
@Override
public void writeCharacters( String text ) throws XMLStreamException
{
boolean useCData = XML_CHARS.matcher( text ).find();
if( useCData )
{
super.writeCData( text );
}
else
{
super.writeCharacters( text );
}
}
}
Run Code Online (Sandbox Code Playgroud)
ra9*_*a9r 10
以下是上述网站引用的代码示例:
import java.io.File;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Document;
public class JaxbCDATASample {
public static void main(String[] args) throws Exception {
// unmarshal a doc
JAXBContext jc = JAXBContext.newInstance("...");
Unmarshaller u = jc.createUnmarshaller();
Object o = u.unmarshal(...);
// create a JAXB marshaller
Marshaller m = jc.createMarshaller();
// get an Apache XMLSerializer configured to generate CDATA
XMLSerializer serializer = getXMLSerializer();
// marshal using the Apache XMLSerializer
m.marshal(o, serializer.asContentHandler());
}
private static XMLSerializer getXMLSerializer() {
// configure an OutputFormat to handle CDATA
OutputFormat of = new OutputFormat();
// specify which of your elements you want to be handled as CDATA.
// The use of the '^' between the namespaceURI and the localname
// seems to be an implementation detail of the xerces code.
// When processing xml that doesn't use namespaces, simply omit the
// namespace prefix as shown in the third CDataElement below.
of.setCDataElements(
new String[] { "ns1^foo", // <ns1:foo>
"ns2^bar", // <ns2:bar>
"^baz" }); // <baz>
// set any other options you'd like
of.setPreserveSpace(true);
of.setIndenting(true);
// create the serializer
XMLSerializer serializer = new XMLSerializer(of);
serializer.setOutputByteStream(System.out);
return serializer;
}
}
Run Code Online (Sandbox Code Playgroud)
出于与Michael Ernst相同的原因,我对这里的大多数答案并不满意.我不能使用他的解决方案,因为我的要求是将CDATA标签放在一组定义的字段中 - 就像raiglstorfer的OutputFormat解决方案一样.
我的解决方案是编组DOM文档,然后执行null XSL转换来执行输出.变形金刚允许您设置哪些元素包含在CDATA标记中.
Document document = ...
jaxbMarshaller.marshal(jaxbObject, document);
Transformer nullTransformer = TransformerFactory.newInstance().newTransformer();
nullTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
nullTransformer.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, "myElement {myNamespace}myOtherElement");
nullTransformer.transform(new DOMSource(document), new StreamResult(writer/stream));
Run Code Online (Sandbox Code Playgroud)
更多信息:http://javacoalface.blogspot.co.uk/2012/09/outputting-cdata-sections-with-jaxb.html
小智 5
以下简单方法在JAX-B中添加了CDATA支持,它本身不支持CDATA:
Et voila,任何CDataString元素都将在Marshall时封装.在解组时,会自动删除.
@a2ndrade的答案的补充。
我在 JDK 8 中找到了一个要扩展的类。但注意到该类位于com.sunpackage.json 中。您可以复制一份代码,以防此类在将来的 JDK 中被删除。
public class CDataContentHandler extends com.sun.xml.internal.txw2.output.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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
如何使用:
JAXBContext jaxbContext = JAXBContext.newInstance(...class);
Marshaller marshaller = jaxbContext.createMarshaller();
StringWriter sw = new StringWriter();
CDataContentHandler cdataHandler = new CDataContentHandler(sw,"utf-8");
marshaller.marshal(gu, cdataHandler);
System.out.println(sw.toString());
Run Code Online (Sandbox Code Playgroud)
结果示例:
<?xml version="1.0" encoding="utf-8"?>
<genericUser>
<password><![CDATA[dskfj>><<]]></password>
<username>UNKNOWN::UNKNOWN</username>
<properties>
<prop2>v2</prop2>
<prop1><![CDATA[v1><]]></prop1>
</properties>
<timestamp/>
<uuid>cb8cbc487ee542ec83e934e7702b9d26</uuid>
</genericUser>
Run Code Online (Sandbox Code Playgroud)