解决webservice中使用XStream输出xml时候转义字符问题

问题:

使用XStream去将对象转为想xml的时候,对象中的一个url字段值具有特殊字符

例如:lsid=B5D453EFABD00D0A878756E0D0B845B9&uiid=B74D04E5EF789344B6392D04161A5144&

经过XStream的toXml方法进行输出的时候,会被转义成如下:

lsid=B5D453EFABD00D0A878756E0D0B845B9&uiid=B74D04E5EF789344B6392D04161A5144&

它将&特殊字符转义成了&,这样可不行,通过webservice接口拿到数据无法直接使用该url了。

解决办法:

1.定义编写器,它将XML输出到打印良好的缩进流中。


/**
 * <p>主要重写特殊字符不转义,源码参考 {@link com.thoughtworks.xstream.io.xml.PrettyPrintWriter}</p>
 * <p>重写的方法:{@link #writeText(String, boolean)}</p>
 */
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;
    }
}
 

2.重写 XppDriver 解析器的HierarchicalStreamWriter方法


/**
 * 重写 XppDriver
 */
public class NoneEscapeAppDriver extends XppDriver {

    @Override
    public HierarchicalStreamWriter createWriter(Writer out) {
        return new NoneEscapePrettyPintWriter(out, getNameCoder());
    }
}

3.使用:

 XStream xStream = new XStream(new NoneEscapeAppDriver());
            xStream.processAnnotations(resultData.getClass());
            String xmlHead = "<?xml version=\"1.0\" encoding=\"gb2312\"?>";

            return xmlHead + xStream.toXML(resultData);

再次输出的时候对象字段的值就没有乱码了。

原文地址:https://blog.csdn.net/sinat_32364425/article/details/102476954

发布了102 篇原创文章 · 获赞 49 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/SoWhatWorld/article/details/104850865