与这个问题非常相似,只是针对Java。
在Java中,推荐使用什么方法来对字符串进行XML输出的编码?这些字符串可能包含像"&"、"<"等字符。
非常简单:使用一个XML库。这样它就会是正确的,而不需要详细了解XML规范的每个细节。
只需使用即可。
<![CDATA[ your text here ]]>
这将允许任何字符,除了结尾的
]]>
因此,您可以包括一些本来是非法的字符,如&和>。例如:
<element><![CDATA[ characters such as & and > are allowed ]]></element>
然而,属性需要进行转义,因为CDATA块不能用于它们。
public static String encodeXML(String s) {
StringBuilder sb = new StringBuilder();
int len = s.length();
for (int i=0;i<len;) {
int c = s.codePointAt(i);
if (c < 0x80) { // ASCII range: test most common case first
if (c < 0x20 && (c != '\t' && c != '\r' && c != '\n')) {
// Illegal XML character, even encoded. Skip or substitute
sb.append("�"); // Unicode replacement character
} else {
switch(c) {
case '&': sb.append("&"); break;
case '>': sb.append(">"); break;
case '<': sb.append("<"); break;
// Uncomment next two if encoding for an XML attribute
// case '\'' sb.append("'"); break;
// case '\"' sb.append("""); break;
// Uncomment next three if you prefer, but not required
// case '\n' sb.append(" "); break;
// case '\r' sb.append(" "); break;
// case '\t' sb.append("	"); break;
default: sb.append((char)c);
}
}
} else if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) {
// Illegal XML character, even encoded. Skip or substitute
sb.append("�"); // Unicode replacement character
} else {
sb.append("&#x");
sb.append(Integer.toHexString(c));
sb.append(';');
}
i += c <= 0xffff ? 1 : 2;
}
return sb.toString();
}
编辑:对于那些坚持认为在处理XML时自己编写代码是愚蠢的人,你可能会想知道,Oracle Java 8(我没有测试其他版本)附带的StAX API无法正确编码CDATA内容:它不会转义内容中的]]>序列。第三方库,即使是Java核心的一部分,也并不总是最佳选择。
试试这个:
String xmlEscapeText(String t) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < t.length(); i++){
char c = t.charAt(i);
switch(c){
case '<': sb.append("<"); break;
case '>': sb.append(">"); break;
case '\"': sb.append("""); break;
case '&': sb.append("&"); break;
case '\'': sb.append("'"); break;
default:
if(c>0x7e) {
sb.append("&#"+((int)c)+";");
}else
sb.append(c);
}
}
return sb.toString();
}
t==null
的情况。 - Myobis以下方法可以给出一个已转义的文本字符串:
public class XMLHelper {
/**
* Returns the string where all non-ascii and <, &, > are encoded as numeric entities. I.e. "<A & B >"
* .... (insert result here). The result is safe to include anywhere in a text field in an XML-string. If there was
* no characters to protect, the original string is returned.
*
* @param originalUnprotectedString
* original string which may contain characters either reserved in XML or with different representation
* in different encodings (like 8859-1 and UFT-8)
* @return
*/
public static String protectSpecialCharacters(String originalUnprotectedString) {
if (originalUnprotectedString == null) {
return null;
}
boolean anyCharactersProtected = false;
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < originalUnprotectedString.length(); i++) {
char ch = originalUnprotectedString.charAt(i);
boolean controlCharacter = ch < 32;
boolean unicodeButNotAscii = ch > 126;
boolean characterWithSpecialMeaningInXML = ch == '<' || ch == '&' || ch == '>';
if (characterWithSpecialMeaningInXML || unicodeButNotAscii || controlCharacter) {
stringBuffer.append("&#" + (int) ch + ";");
anyCharactersProtected = true;
} else {
stringBuffer.append(ch);
}
}
if (anyCharactersProtected == false) {
return originalUnprotectedString;
}
return stringBuffer.toString();
}
}
StringEscapeUtils.escapeXml()
方法不会转义控制字符(小于0x20)。XML 1.1允许控制字符,而XML 1.0则不允许。例如,XStream.toXML()
会将Java对象的控制字符序列化为XML,但XML 1.0解析器将拒绝该XML。
如果想要使用Apache commons-lang转义控制字符,请使用以下方法:
NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
public String escapeXml(String s) {
return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'");
}
replaceAll
非常低效,尤其是针对大字符串。每次调用都会创建一个新的String对象,直到被垃圾回收。而且,每次调用都需要再次循环遍历字符串。这可以合并为一次手动循环,在每次迭代中与每个目标字符进行比较。 - daiscogStringEscapeUtils.escapeXml10()
StringEscapeUtils.escapeXml11()
StringEscapeUtils.escapeXml()
现已过时,但在过去经常被使用请记得包含依赖项:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version> <!--check current version! -->
</dependency>
虽然理想主义者会建议使用XML库,但在我看来,如果您对XML有基本的了解,那么常识和性能都会告诉您应该一直使用模板。这样做可能更易读。不过,使用库的转义例程可能是一个好主意。
请考虑这一点:XML 原本就是为人类编写而设计的。
当您的XML作为“对象”更好地模拟您的问题时,请使用生成XML的库。例如,如果可插入模块参与构建此XML的过程。
编辑:至于如何在模板中实际转义XML,使用CDATA或JSTL中的escapeXml(string)
是两个好方法,可以像这样使用escapeXml(string)
:
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<item>${fn:escapeXml(value)}</item>
commons-lang
еә“дёӯзҡ„StringEscapeUtils.escapeXml(str)
еҮҪж•°иҝӣиЎҢXMLеӯ—з¬ҰдёІиҪ¬д№үгҖӮжҲ‘еңЁApp Engineеә”з”ЁзЁӢеәҸдёӯдҪҝз”Ёе®ғпјҢж•ҲжһңйқһеёёеҘҪгҖӮиҝҷжҳҜиҜҘеҮҪж•°зҡ„Java DocгҖӮ - Oleg K\t
、\n
和\r
。 - Lii\t
、\n
或者\r
需要进行转义吗? - BetlistaStringEscapeUtils.escapeXml()
不会转义控制字符,在许多情况下这些字符在 XML 中是无效的。 - Chincommons-lang
迁移到了commons-text
。 - Gregor