xstream特殊字符转义问题

xstream特殊字符被转义问题

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 = "&#x0;".toCharArray();
    private static final char[] AMP = "&amp;".toCharArray();
    private static final char[] LT = "&lt;".toCharArray();
    private static final char[] GT = "&gt;".toCharArray();
    private static final char[] CR = "&#xd;".toCharArray();
    private static final char[] QUOT = "&quot;".toCharArray();
    private static final char[] APOS = "&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;
    }
}

问题解决!!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值