mirror of
https://gitee.com/dromara/hutool.git
synced 2025-05-04 04:37:59 +08:00
fix escape bug
This commit is contained in:
parent
a97e967ecd
commit
949c7a856e
@ -3,11 +3,13 @@
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.7.3 (2021-06-20)
|
||||
# 5.7.3 (2021-06-24)
|
||||
|
||||
### 🐣新特性
|
||||
* 【core 】 增加Convert.toSet方法(issue#I3XFG2@Gitee)
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【json 】 修复XML转义字符的问题(issue#I3XH09@Gitee)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -22,6 +22,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -576,7 +577,7 @@ public class Convert {
|
||||
* @param <T> 元素类型
|
||||
* @param elementType 集合中元素类型
|
||||
* @param value 被转换的值
|
||||
* @return {@link List}
|
||||
* @return {@link ArrayList}
|
||||
* @since 4.1.20
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -584,6 +585,20 @@ public class Convert {
|
||||
return (List<T>) toCollection(ArrayList.class, elementType, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为HashSet
|
||||
*
|
||||
* @param <T> 元素类型
|
||||
* @param elementType 集合中元素类型
|
||||
* @param value 被转换的值
|
||||
* @return {@link HashSet}
|
||||
* @since 5.7.3
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Set<T> toSet(Class<T> elementType, Object value) {
|
||||
return (Set<T>) toCollection(HashSet.class, elementType, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Map
|
||||
*
|
||||
|
@ -1,7 +1,6 @@
|
||||
package cn.hutool.core.text.escape;
|
||||
|
||||
import cn.hutool.core.text.replacer.LookupReplacer;
|
||||
import cn.hutool.core.text.replacer.ReplacerChain;
|
||||
|
||||
/**
|
||||
* HTML4的ESCAPE
|
||||
@ -10,16 +9,9 @@ import cn.hutool.core.text.replacer.ReplacerChain;
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
public class Html4Escape extends ReplacerChain {
|
||||
public class Html4Escape extends XmlEscape {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected static final String[][] BASIC_ESCAPE = { //
|
||||
{ "\"", """ }, // " - double-quote
|
||||
{ "&", "&" }, // & - ampersand
|
||||
{ "<", "<" }, // < - less-than
|
||||
{ ">", ">" }, // > - greater-than
|
||||
};
|
||||
|
||||
protected static final String[][] ISO8859_1_ESCAPE = { //
|
||||
{ "\u00A0", " " }, // non-breaking space
|
||||
{ "\u00A1", "¡" }, // inverted exclamation mark
|
||||
@ -317,7 +309,7 @@ public class Html4Escape extends ReplacerChain {
|
||||
};
|
||||
|
||||
public Html4Escape() {
|
||||
addChain(new LookupReplacer(BASIC_ESCAPE));
|
||||
super();
|
||||
addChain(new LookupReplacer(ISO8859_1_ESCAPE));
|
||||
addChain(new LookupReplacer(HTML40_EXTENDED_ESCAPE));
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package cn.hutool.core.text.escape;
|
||||
|
||||
import cn.hutool.core.text.replacer.LookupReplacer;
|
||||
import cn.hutool.core.text.replacer.ReplacerChain;
|
||||
|
||||
/**
|
||||
* HTML4的UNESCAPE
|
||||
@ -9,20 +8,15 @@ import cn.hutool.core.text.replacer.ReplacerChain;
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
public class Html4Unescape extends ReplacerChain {
|
||||
public class Html4Unescape extends XmlUnescape {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected static final String[][] BASIC_UNESCAPE = InternalEscapeUtil.invert(Html4Escape.BASIC_ESCAPE);
|
||||
protected static final String[][] ISO8859_1_UNESCAPE = InternalEscapeUtil.invert(Html4Escape.ISO8859_1_ESCAPE);
|
||||
protected static final String[][] HTML40_EXTENDED_UNESCAPE = InternalEscapeUtil.invert(Html4Escape.HTML40_EXTENDED_ESCAPE);
|
||||
// issue#1118
|
||||
protected static final String[][] OTHER_UNESCAPE = new String[][]{new String[]{"'", "'"}};
|
||||
|
||||
public Html4Unescape() {
|
||||
addChain(new LookupReplacer(BASIC_UNESCAPE));
|
||||
super();
|
||||
addChain(new LookupReplacer(ISO8859_1_UNESCAPE));
|
||||
addChain(new LookupReplacer(HTML40_EXTENDED_UNESCAPE));
|
||||
addChain(new LookupReplacer(OTHER_UNESCAPE));
|
||||
addChain(new NumericEntityUnescaper());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
package cn.hutool.core.text.escape;
|
||||
|
||||
import cn.hutool.core.text.replacer.LookupReplacer;
|
||||
import cn.hutool.core.text.replacer.ReplacerChain;
|
||||
|
||||
/**
|
||||
* XML特殊字符转义<br>
|
||||
* 见:https://stackoverflow.com/questions/1091945/what-characters-do-i-need-to-escape-in-xml-documents<br>
|
||||
*
|
||||
* <pre>
|
||||
* & (ampersand) 替换为 &amp;
|
||||
* < (less than) 替换为 &lt;
|
||||
* > (greater than) 替换为 &gt;
|
||||
* " (double quote) 替换为 &quot;
|
||||
* ' (single quote / apostrophe) 替换为 &apos;
|
||||
* </pre>
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.2
|
||||
*/
|
||||
public class XmlEscape extends ReplacerChain {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected static final String[][] BASIC_ESCAPE = { //
|
||||
{"'", "'"}, // " - single-quote
|
||||
{"\"", """}, // " - double-quote
|
||||
{"&", "&"}, // & - ampersand
|
||||
{"<", "<"}, // < - less-than
|
||||
{">", ">"}, // > - greater-than
|
||||
};
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*/
|
||||
public XmlEscape() {
|
||||
addChain(new LookupReplacer(BASIC_ESCAPE));
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cn.hutool.core.text.escape;
|
||||
|
||||
import cn.hutool.core.text.replacer.LookupReplacer;
|
||||
import cn.hutool.core.text.replacer.ReplacerChain;
|
||||
|
||||
/**
|
||||
* XML的UNESCAPE
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.2
|
||||
*/
|
||||
public class XmlUnescape extends ReplacerChain {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected static final String[][] BASIC_UNESCAPE = InternalEscapeUtil.invert(XmlEscape.BASIC_ESCAPE);
|
||||
|
||||
public XmlUnescape() {
|
||||
addChain(new LookupReplacer(BASIC_UNESCAPE));
|
||||
addChain(new NumericEntityUnescaper());
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package cn.hutool.core.text.replacer;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import cn.hutool.core.lang.Replacer;
|
||||
import cn.hutool.core.text.StrBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 抽象字符串替换类<br>
|
||||
* 通过实现replace方法实现局部替换逻辑
|
||||
@ -28,18 +28,18 @@ public abstract class StrReplacer implements Replacer<CharSequence>, Serializabl
|
||||
@Override
|
||||
public CharSequence replace(CharSequence t) {
|
||||
final int len = t.length();
|
||||
final StrBuilder strBuillder = StrBuilder.create(len);
|
||||
final StrBuilder builder = StrBuilder.create(len);
|
||||
int pos = 0;//当前位置
|
||||
int consumed;//处理过的字符数
|
||||
while (pos < len) {
|
||||
consumed = replace(t, pos, strBuillder);
|
||||
consumed = replace(t, pos, builder);
|
||||
if (0 == consumed) {
|
||||
//0表示未处理或替换任何字符,原样输出本字符并从下一个字符继续
|
||||
strBuillder.append(t.charAt(pos));
|
||||
builder.append(t.charAt(pos));
|
||||
pos++;
|
||||
}
|
||||
pos += consumed;
|
||||
}
|
||||
return strBuillder;
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package cn.hutool.core.util;
|
||||
import cn.hutool.core.lang.Filter;
|
||||
import cn.hutool.core.text.escape.Html4Escape;
|
||||
import cn.hutool.core.text.escape.Html4Unescape;
|
||||
import cn.hutool.core.text.escape.XmlEscape;
|
||||
import cn.hutool.core.text.escape.XmlUnescape;
|
||||
|
||||
/**
|
||||
* 转义和反转义工具类Escape / Unescape<br>
|
||||
@ -24,6 +26,37 @@ public class EscapeUtil {
|
||||
|| StrUtil.contains(NOT_ESCAPE_CHARS, c)
|
||||
);
|
||||
|
||||
/**
|
||||
* 转义XML中的特殊字符<br>
|
||||
* <pre>
|
||||
* & (ampersand) 替换为 &amp;
|
||||
* < (less than) 替换为 &lt;
|
||||
* > (greater than) 替换为 &gt;
|
||||
* " (double quote) 替换为 &quot;
|
||||
* ' (single quote / apostrophe) 替换为 &apos;
|
||||
* </pre>
|
||||
*
|
||||
* @param xml XML文本
|
||||
* @return 转义后的文本
|
||||
* @since 5.7.2
|
||||
*/
|
||||
public static String escapeXml(CharSequence xml) {
|
||||
XmlEscape escape = new XmlEscape();
|
||||
return escape.replace(xml).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 反转义XML中的特殊字符
|
||||
*
|
||||
* @param xml XML文本
|
||||
* @return 转义后的文本
|
||||
* @since 5.7.2
|
||||
*/
|
||||
public static String unescapeXml(CharSequence xml) {
|
||||
XmlUnescape unescape = new XmlUnescape();
|
||||
return unescape.replace(xml).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义HTML4中的特殊字符
|
||||
*
|
||||
|
@ -986,7 +986,7 @@ public class XmlUtil {
|
||||
* @since 4.0.8
|
||||
*/
|
||||
public static String escape(String string) {
|
||||
return EscapeUtil.escape(string);
|
||||
return EscapeUtil.escapeHtml4(string);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -998,7 +998,7 @@ public class XmlUtil {
|
||||
* @since 5.0.6
|
||||
*/
|
||||
public static String unescape(String string) {
|
||||
return EscapeUtil.unescape(string);
|
||||
return EscapeUtil.unescapeHtml4(string);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,12 +4,12 @@ import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EscapeUtilTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void escapeHtml4Test() {
|
||||
String escapeHtml4 = EscapeUtil.escapeHtml4("<a>你好</a>");
|
||||
Assert.assertEquals("<a>你好</a>", escapeHtml4);
|
||||
|
||||
|
||||
String result = EscapeUtil.unescapeHtml4("振荡器类型");
|
||||
Assert.assertEquals("振荡器类型", result);
|
||||
|
||||
@ -39,9 +39,9 @@ public class EscapeUtilTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void escapeSinleQuotesTest(){
|
||||
public void escapeSingleQuotesTest(){
|
||||
String str = "'some text with single quotes'";
|
||||
final String s = EscapeUtil.escapeHtml4(str);
|
||||
Assert.assertEquals(str, s);
|
||||
Assert.assertEquals("'some text with single quotes'", s);
|
||||
}
|
||||
}
|
||||
|
@ -287,4 +287,11 @@ public class XmlUtilTest {
|
||||
String format = XmlUtil.toStr(xml,"GBK",true);
|
||||
Console.log(format);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void escapeTest(){
|
||||
String a = "<>";
|
||||
final String escape = XmlUtil.escape(a);
|
||||
Console.log(escape);
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,24 @@ public enum Padding {
|
||||
* 0补码,即不满block长度时使用0填充
|
||||
*/
|
||||
ZeroPadding,
|
||||
/**
|
||||
* This padding for block ciphers is described in 5.2 Block Encryption Algorithms in the W3C's "XML Encryption Syntax and Processing" document.
|
||||
*/
|
||||
ISO10126Padding,
|
||||
/**
|
||||
* Optimal Asymmetric Encryption Padding scheme defined in PKCS1
|
||||
*/
|
||||
OAEPPadding,
|
||||
/**
|
||||
* The padding scheme described in PKCS #1, used with the RSA algorithm
|
||||
*/
|
||||
PKCS1Padding,
|
||||
/**
|
||||
* The padding scheme described in RSA Laboratories, "PKCS #5: Password-Based Encryption Standard," version 1.5, November 1993.
|
||||
*/
|
||||
PKCS5Padding,
|
||||
/**
|
||||
* The padding scheme defined in the SSL Protocol Version 3.0, November 18, 1996, section 5.2.3.2 (CBC block cipher)
|
||||
*/
|
||||
SSL3Padding
|
||||
}
|
||||
|
@ -331,11 +331,11 @@ public class XML {
|
||||
if (i > 0) {
|
||||
sb.append('\n');
|
||||
}
|
||||
sb.append(EscapeUtil.escapeHtml4(val.toString()));
|
||||
sb.append(EscapeUtil.escapeXml(val.toString()));
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
sb.append(EscapeUtil.escapeHtml4(value.toString()));
|
||||
sb.append(EscapeUtil.escapeXml(value.toString()));
|
||||
}
|
||||
|
||||
// Emit an array of similar keys
|
||||
@ -377,7 +377,7 @@ public class XML {
|
||||
|
||||
}
|
||||
|
||||
if (object.getClass().isArray()) {
|
||||
if (ArrayUtil.isArray(object)) {
|
||||
object = new JSONArray(object);
|
||||
}
|
||||
|
||||
@ -392,10 +392,12 @@ public class XML {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
String string = EscapeUtil.escapeHtml4(object.toString());
|
||||
String string = EscapeUtil.escapeXml(object.toString());
|
||||
return (tagName == null) ?
|
||||
"\"" + string + "\"" : (string.length() == 0) ? "<" + tagName + "/>"
|
||||
: "<" + tagName + ">" + string + "</" + tagName + ">";
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -14,4 +14,15 @@ public class XMLTest {
|
||||
Assert.assertEquals("<aaa>你好</aaa><键2>test</键2>", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void escapeTest(){
|
||||
String xml = "<a>•</a>";
|
||||
JSONObject jsonObject = XML.toJSONObject(xml);
|
||||
|
||||
Assert.assertEquals("{\"a\":\"•\"}", jsonObject.toString());
|
||||
|
||||
String xml2 = XML.toXml(JSONUtil.parseObj(jsonObject));
|
||||
Assert.assertEquals(xml, xml2);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user