【发布时间】:2010-10-01 03:47:08
【问题描述】:
与this question 非常相似,Java 除外。
在 Java 中为 XML 输出编码字符串的推荐方法是什么。字符串可能包含“&”、“
【问题讨论】:
与this question 非常相似,Java 除外。
在 Java 中为 XML 输出编码字符串的推荐方法是什么。字符串可能包含“&”、“
【问题讨论】:
正如其他人所提到的,使用 XML 库是最简单的方法。如果您确实想逃避自己,可以查看Apache Commons Lang 库中的StringEscapeUtils。
【讨论】:
commons-lang 的StringEscapeUtils.escapeXml(str)。我在 App Engine 应用程序中使用它 - 像魅力一样工作。这是此功能的Java Doc:
\t、\n 和\r。
commons-lang移动到commons-text
非常简单:使用 XML 库。这样一来,它实际上是正确,而不需要详细了解 XML 规范。
【讨论】:
随便用。
<![CDATA[ your text here ]]>
这将允许除结尾之外的任何字符
]]>
因此您可以包含非法字符,例如 & 和 >。例如。
<element><![CDATA[ characters such as & and > are allowed ]]></element>
但是,属性需要转义,因为 CDATA 块不能用于它们。
【讨论】:
试试这个:
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的情况。
这对我来说很好地提供了文本字符串的转义版本:
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();
}
}
【讨论】:
这个问题已经八年了,仍然不是一个完全正确的答案!不,您不必导入整个第三方 API 来完成这个简单的任务。不好的建议。
以下方法将:
我已尝试针对最常见的情况进行优化,同时仍确保您可以通过管道传输 /dev/random 并获得 XML 中的有效字符串。
public static String encodeXML(CharSequence s) {
StringBuilder sb = new StringBuilder();
int len = s.length();
for (int i=0;i<len;i++) {
int c = s.charAt(i);
if (c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
c = ((c-0xd7c0)<<10) | (s.charAt(++i)&0x3ff); // UTF16 decode
}
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(';');
}
}
return sb.toString();
}
编辑:对于那些继续坚持在有非常好的 Java API 来处理 XML 时为此编写自己的代码是愚蠢的人,您可能想知道 Oracle Java 8 中包含的 StAX API (我没有测试过其他人)未能正确编码 CDATA 内容:它不会转义 ]]> 内容中的序列。第三方库,即使是 Java 核心的一部分,也并不总是最好的选择。
【讨论】:
StringEscapeUtils.escapeXml() 不转义控制字符 (XStream.toXML() 会愉快地将 Java 对象的控制字符序列化为 XML,而 XML 1.0 解析器将拒绝。
要使用 Apache commons-lang 转义控制字符,请使用
NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
【讨论】:
public String escapeXml(String s) {
return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'");
}
【讨论】:
replaceAll 调用效率非常低,尤其是对于大字符串。每次调用都会创建一个新的 String 对象,该对象将一直存在,直到垃圾收集为止。此外,每次调用都需要再次循环字符串。这可以合并到一个手动循环中,并在每次迭代中与每个目标字符进行比较。
对于那些寻求最快编写解决方案的人:使用来自apache commons-lang的方法:
StringEscapeUtils.escapeXml10() 用于 xml 1.0StringEscapeUtils.escapeXml11() 用于 xml 1.1StringEscapeUtils.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,使用 JSTL 中的 CDATA 或 escapeXml(string) 是两个很好的解决方案,escapeXml(string) 可以这样使用:
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<item>${fn:escapeXml(value)}</item>
【讨论】:
StringEscapeUtils.escapeXml() 的行为已从 Commons Lang 2.5 更改为 3.0。 它现在不再转义大于 0x7f 的 Unicode 字符。
这是一件好事,旧方法有点急于逃避可以插入到 utf8 文档中的实体。
Google Guava 11.0 中包含的新转义器似乎也很有希望: http://code.google.com/p/guava-libraries/issues/detail?id=799
【讨论】:
注意:您的问题是关于转义,而不是编码。转义是使用
首先,就像其他人所说的那样,使用 XML 库。 XML 看起来很简单,但编码+转义的东西是黑暗的巫术(一旦你遇到变音符号和日语以及其他奇怪的东西,比如“full width digits”(FF11; 是 1),你就会注意到它)。保持 XML 可读性是西西弗斯的任务。
我建议永远不要试图在 XML 中的文本编码和转义方面变得聪明。但不要让这阻止你尝试;只要记住它咬你的时候(它会咬你的)。
也就是说,如果您只使用 UTF-8,为了使内容更具可读性,您可以考虑以下策略:
<![CDATA[ ... ]]>
我在 SQL 编辑器中使用它,它允许开发人员将 SQL 从第三方 SQL 工具剪切和粘贴到 XML 中,而不必担心转义。这是可行的,因为在我们的例子中 SQL 不能包含变音符号,所以我很安全。
【讨论】:
虽然我原则上同意 Jon Skeet,但有时我无法选择使用外部 XML 库。而且我发现在 Java 中包含的标准 XML 库中没有转义/取消转义一个简单值(属性或标签,不是完整文档)的两个函数很奇特。
因此,根据我在这里和其他地方看到的不同答案,这是我最终创建的解决方案(没有什么可以作为简单的复制/粘贴):
public final static String ESCAPE_CHARS = "<>&\"\'";
public final static List<String> ESCAPE_STRINGS = Collections.unmodifiableList(Arrays.asList(new String[] {
"<"
, ">"
, "&"
, """
, "'"
}));
private static String UNICODE_NULL = "" + ((char)0x00); //null
private static String UNICODE_LOW = "" + ((char)0x20); //space
private static String UNICODE_HIGH = "" + ((char)0x7f);
//should only be used for the content of an attribute or tag
public static String toEscaped(String content) {
String result = content;
if ((content != null) && (content.length() > 0)) {
boolean modified = false;
StringBuilder stringBuilder = new StringBuilder(content.length());
for (int i = 0, count = content.length(); i < count; ++i) {
String character = content.substring(i, i + 1);
int pos = ESCAPE_CHARS.indexOf(character);
if (pos > -1) {
stringBuilder.append(ESCAPE_STRINGS.get(pos));
modified = true;
}
else {
if ( (character.compareTo(UNICODE_LOW) > -1)
&& (character.compareTo(UNICODE_HIGH) < 1)
) {
stringBuilder.append(character);
}
else {
//Per URL reference below, Unicode null character is always restricted from XML
//URL: https://en.wikipedia.org/wiki/Valid_characters_in_XML
if (character.compareTo(UNICODE_NULL) != 0) {
stringBuilder.append("&#" + ((int)character.charAt(0)) + ";");
}
modified = true;
}
}
}
if (modified) {
result = stringBuilder.toString();
}
}
return result;
}
上面包含了几个不同的东西:
在某个时候,我会写这个函数的反转,toUnescaped()。我只是今天没有时间这样做。当我这样做时,我会用代码更新这个答案。 :)
【讨论】:
如果您正在寻找一个库来完成这项工作,请尝试:
Guava 26.0 记录了here
return XmlEscapers.xmlContentEscaper().escape(text);
注意:还有一个
xmlAttributeEscaper()
Apache Commons Text 1.4 记录了here
StringEscapeUtils.escapeXml11(text)
注意:还有一个
escapeXml10()方法
【讨论】:
要转义 XML 字符,最简单的方法是使用 Apache Commons Lang 项目,JAR 可从以下位置下载:http://commons.apache.org/lang/
类是这样的:org.apache.commons.lang3.StringEscapeUtils;
它有一个名为“escapeXml”的方法,它将返回一个适当转义的字符串。
【讨论】:
您可以使用Enterprise Security API (ESAPI) library,它提供了encodeForXML 和encodeForXMLAttribute 等方法。看一下Encoder接口的文档;它还包含如何创建DefaultEncoder 实例的示例。
【讨论】:
这是一个简单的解决方案,它也非常适合编码重音字符!
String in = "Hi Lârry & Môe!";
StringBuilder out = new StringBuilder();
for(int i = 0; i < in.length(); i++) {
char c = in.charAt(i);
if(c < 31 || c > 126 || "<>\"'\\&".indexOf(c) >= 0) {
out.append("&#" + (int) c + ";");
} else {
out.append(c);
}
}
System.out.printf("%s%n", out);
输出
Hi Lârry & Môe!
【讨论】:
尝试使用 Apache XML 序列化器对 XML 进行编码
//Serialize DOM
OutputFormat format = new OutputFormat (doc);
// as a String
StringWriter stringOut = new StringWriter ();
XMLSerializer serial = new XMLSerializer (stringOut,
format);
serial.serialize(doc);
// Display the XML
System.out.println(stringOut.toString());
【讨论】:
只需替换
& with &
对于其他角色:
> with >
< with <
\" with "
' with '
【讨论】:
这是我在到处寻找解决方案后发现的:
获取 Jsoup 库:
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
然后:
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Entities
import org.jsoup.parser.Parser
String xml = '''<?xml version = "1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV = "http://www.w3.org/2001/12/soap-envelope"
SOAP-ENV:encodingStyle = "http://www.w3.org/2001/12/soap-encoding">
<SOAP-ENV:Body xmlns:m = "http://www.example.org/quotations">
<m:GetQuotation>
<m:QuotationsName> MiscroSoft@G>>gle.com </m:QuotationsName>
</m:GetQuotation>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>'''
Document doc = Jsoup.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")), "UTF-8", "", Parser.xmlParser())
doc.outputSettings().charset("UTF-8")
doc.outputSettings().escapeMode(Entities.EscapeMode.base)
println doc.toString()
希望这对某人有所帮助
【讨论】:
我在这里创建了我的包装器,希望对你有很大帮助,Click here你可以根据你的要求进行修改
【讨论】: