1.问题描述
如上图显示,类似于“”,‘’这些特殊符号使用xstream,被转义成特殊字符
代码如下:
public class XmlUtils {
private static XStream xstream=createXStream();
private static XStream createXStream() {
StaxDriver staxDriver=new StaxDriver();
//不转义字符
staxDriver.getOutputFactory().setProperty("escapeCharacters", false);
xstream = new XStream(staxDriver);
xstream.autodetectAnnotations(true);
return xstream;
}
/**
* 在指定路径生成xml文件
*
* @param t
* @param xmlPath
* @param <T>
* @throws IOException
*/
public static <T> void toXML(T t, Path xmlPath) throws IOException {
File file = new File(xmlPath.toUri());
if (!file.exists()) {
file.createNewFile();
}
PrettyPrintWriter prettyPrintWriter = new PrettyPrintWriter(new FileWriter(file));
xstream.marshal(t, prettyPrintWriter);
prettyPrintWriter.close();
}
public static <T> T fromXML(Path xmlPath) throws MalformedURLException {
File file = new File(xmlPath.toUri());
return (T) xstream.fromXML(file);
}
/**
* 生成xml字符串
*
* @param t
* @param <T>
* @return
*/
public static <T> String toXML(T t) {
return xstream.toXML(t);
}
public static <T> T fromXML(String xml) {
return (T) xstream.fromXML(xml);
}
/**
* 别名
*
* @param aliasMap 需要起别名的class,如果没有别名,Xstream会默认以Class的全限定名作为节点名称
*/
public static void alias(Map<String, Class> aliasMap) {
aliasMap.forEach((k, v) -> xstream.alias(k, v));
}
public static XStream getXstream() {
return xstream;
}
}
原因: PrettyPrintWriter 这里有个writeText方法这里,没有对特殊字符做了转义
2.解决方案
定义编写器,对特殊字符不做转义
import com.thoughtworks.xstream.core.util.FastStack;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.AbstractWriter;
import com.thoughtworks.xstream.io.StreamException;
import com.thoughtworks.xstream.io.naming.NameCoder;
import java.io.Writer;
/**
* @author liangwt
* @create 2019/10/16
* @Description :
* @since 1.0.0
*/
public class NoneEscapePrettyPintWriter extends AbstractWriter {
public static int XML_QUIRKS = -1;
public static int XML_1_0 = 0;
public static int XML_1_1 = 1;
private final QuickWriter writer;
private final FastStack elementStack = new FastStack(16);
private final char[] lineIndenter;
private final int mode;
private boolean tagInProgress;
protected int depth;
private boolean readyForNewLine;
private boolean tagIsEmpty;
private String newLine;
private static final char[] NULL = "�".toCharArray();
private static final char[] AMP = "&".toCharArray();
private static final char[] LT = "<".toCharArray();
private static final char[] GT = ">".toCharArray();
private static final char[] CR = "
".toCharArray();
private static final char[] QUOT = """.toCharArray();
private static final char[] APOS = "'".toCharArray();
private static final char[] CLOSE = "</".toCharArray();
private NoneEscapePrettyPintWriter(
Writer writer, int mode, char[] lineIndenter, NameCoder nameCoder,
String newLine) {
super(nameCoder);
this.writer = new QuickWriter(writer);
this.lineIndenter = lineIndenter;
this.newLine = newLine;
this.mode = mode;
if (mode < XML_QUIRKS || mode > XML_1_1) {
throw new IllegalArgumentException("Not a valid XML mode");
}
}
/**
* @since 1.4
*/
public NoneEscapePrettyPintWriter(Writer writer, NameCoder nameCoder) {
this(writer, XML_QUIRKS, new char[]{' ', ' '}, nameCoder, "\n");
}
public void startNode(String name) {
String escapedName = encodeNode(name);
tagIsEmpty = false;
finishTag();
writer.write('<');
writer.write(escapedName);
elementStack.push(escapedName);
tagInProgress = true;
depth++;
readyForNewLine = true;
tagIsEmpty = true;
}
public void startNode(String name, Class clazz) {
startNode(name);
}
public void setValue(String text) {
readyForNewLine = false;
tagIsEmpty = false;
finishTag();
writeText(writer, text);
}
public void addAttribute(String key, String value) {
writer.write(' ');
writer.write(encodeAttribute(key));
writer.write('=');
writer.write('\"');
writeAttributeValue(writer, value);
writer.write('\"');
}
protected void writeAttributeValue(QuickWriter writer, String text) {
writeText(text, true);
}
protected void writeText(QuickWriter writer, String text) {
writeText(text, false);
}
private void writeText(String text, boolean isAttribute) {
int length = text.length();
for (int i = 0; i < length; i++) {
char c = text.charAt(i);
switch (c) {
case '\0':
if (mode == XML_QUIRKS) {
this.writer.write(NULL);
} else {
throw new StreamException("Invalid character 0x0 in XML stream");
}
break;
case '&':
if (isAttribute)
this.writer.write(AMP);
else
this.writer.write(c);
break;
case '<':
if (isAttribute)
this.writer.write(LT);
else
this.writer.write(c);
break;
case '>':
if (isAttribute)
this.writer.write(GT);
else
this.writer.write(c);
break;
case '"':
if (isAttribute)
this.writer.write(QUOT);
else
this.writer.write(c);
break;
case '\'':
if (isAttribute)
this.writer.write(APOS);
else
this.writer.write(c);
break;
case '\r':
if (isAttribute)
this.writer.write(CR);
else
this.writer.write(c);
break;
case '\t':
case '\n':
if (!isAttribute) {
this.writer.write(c);
break;
}
default:
if (Character.isDefined(c) && !Character.isISOControl(c)) {
if (mode != XML_QUIRKS) {
if (c > '\ud7ff' && c < '\ue000') {
throw new StreamException("Invalid character 0x"
+ Integer.toHexString(c)
+ " in XML stream");
}
}
this.writer.write(c);
} else {
if (mode == XML_1_0) {
if (c < 9
|| c == '\u000b'
|| c == '\u000c'
|| c == '\u000e'
|| (c >= '\u000f' && c <= '\u001f')) {
throw new StreamException("Invalid character 0x"
+ Integer.toHexString(c)
+ " in XML 1.0 stream");
}
}
if (mode != XML_QUIRKS) {
if (c == '\ufffe' || c == '\uffff') {
throw new StreamException("Invalid character 0x"
+ Integer.toHexString(c)
+ " in XML stream");
}
}
this.writer.write("&#x");
this.writer.write(Integer.toHexString(c));
this.writer.write(';');
}
}
}
}
public void endNode() {
depth--;
if (tagIsEmpty) {
writer.write('/');
readyForNewLine = false;
finishTag();
elementStack.popSilently();
} else {
finishTag();
writer.write(CLOSE);
writer.write((String) elementStack.pop());
writer.write('>');
}
readyForNewLine = true;
if (depth == 0) {
writer.flush();
}
}
private void finishTag() {
if (tagInProgress) {
writer.write('>');
}
tagInProgress = false;
if (readyForNewLine) {
endOfLine();
}
readyForNewLine = false;
tagIsEmpty = false;
}
protected void endOfLine() {
writer.write(getNewLine());
for (int i = 0; i < depth; i++) {
writer.write(lineIndenter);
}
}
public void flush() {
writer.flush();
}
public void close() {
writer.close();
}
/**
* Retrieve the line terminator.
* <p>
* This method returns always a line feed, since according the XML specification any parser
* must ignore a carriage return. Overload this method, if you need different behavior.
*
* @return the line terminator
* @since 1.3
*/
protected String getNewLine() {
return newLine;
}
}
重写 XppDriver 解析器的HierarchicalStreamWriter方法
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import java.io.Writer;
/**
* @author liangwt
* @create 2019/10/16
* @Description :
* @since 1.0.0
*/
public class NoneEscapeAppDriver extends XppDriver {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new NoneEscapePrettyPintWriter(out, getNameCoder());
}
}
最后调用
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.StaxDriver;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Path;
import java.util.Map;
/**
* @author liangwt
* @create 2019/10/21
* @Description :
* @since 1.0.0
*/
public class XmlUtils {
private static XStream xstream=createXStream();
private static XStream createXStream() {
xstream = new XStream(new NoneEscapeAppDriver());
xstream.autodetectAnnotations(true);
return xstream;
}
/**
* 在指定路径生成xml文件
*
* @param t
* @param xmlPath
* @param <T>
* @throws IOException
*/
public static <T> void toXML(T t, Path xmlPath) throws IOException {
File file = new File(xmlPath.toUri());
if (!file.exists()) {
file.createNewFile();
}
xstream.processAnnotations(t.getClass());
FileOutputStream fos = new FileOutputStream(xmlPath.toString());
fos.write(xstream.toXML(t).getBytes());
fos.close();
}
public static <T> T fromXML(Path xmlPath) throws MalformedURLException {
File file = new File(xmlPath.toUri());
return (T) xstream.fromXML(file);
}
/**
* 生成xml字符串
*
* @param t
* @param <T>
* @return
*/
public static <T> String toXML(T t) {
return xstream.toXML(t);
}
public static <T> T fromXML(String xml) {
return (T) xstream.fromXML(xml);
}
/**
* 别名
*
* @param aliasMap 需要起别名的class,如果没有别名,Xstream会默认以Class的全限定名作为节点名称
*/
public static void alias(Map<String, Class> aliasMap) {
aliasMap.forEach((k, v) -> xstream.alias(k, v));
}
public static XStream getXstream() {
return xstream;
}
}
问题解决!!