用Java编码XML文本数据的最佳方法是什么?
非常类似于这个问题 ,除了Java。
在Java中为XML输出编码string的推荐方法是什么? 这些string可能包含“&”,“<”等字符
非常简单:使用XML库。 这样,它实际上是正确的,而不需要详细了解XML规范的位。
正如其他人所说,使用XML库是最简单的方法。 如果你想逃避自己,你可以看看Apache Commons Lang库中的StringEscapeUtils
。
只是使用。
<![CDATA[ your text here ]]>
这将允许除结尾之外的任何字符
]]>
所以你可以包含非法的字符,如&和>。 例如。
<element><![CDATA[ characters such as & and > are allowed ]]></element>
但是,由于CDATA块不能用于他们,属性将需要被转义。
这对我提供一个文本string的转义版本很有效:
public class XMLHelper { /** * Returns the string where all non-ascii and <, &, > are encoded as numeric entities. Ie "<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(); } }
尝试这个:
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(); }
虽然理想主义说使用XML库,恕我直言,如果你有一个XML的基本思想,那么常识和性能表示一直模板。 这可以说是更可读。 虽然使用图书馆的逃避例程可能是一个好主意。
考虑一下:XML 本来就是由人类写的。
将XML作为“对象”更好地模拟问题时,使用库来生成XML。 例如,如果可插入模块参与构build这个XML的过程。
编辑:至于如何实际上在模板中转义XML,从JSTL使用CDATA或escapeXml(string)
是两个很好的解决scheme, 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中包含的新增function也显得很有前途: http : //code.google.com/p/guava-libraries/issues/detail? id=799
StringEscapeUtils.escapeXml()
不会转义控制字符(<0x20)。 XML 1.1允许控制字符; XML 1.0不。 例如, XStream.toXML()
将会愉快地将Java对象的控制字符序列化为XML,XML 1.0parsing器将拒绝这种控制字符。
要用Apache commons-lang转义控制字符,请使用
NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
注意:你的问题是关于转义 ,而不是编码 。 转义使用<等等来允许parsing器区分“这是一个XML命令”和“这是一些文本”。 编码是您在XML标题(UTF-8,ISO-8859-1等)中指定的内容。
首先,像其他人所说,使用XML库。 XML看起来很简单,但是编码+转义的东西是黑巫术(当你遇到元音变音和日文以及其他奇怪的东西,例如“ 全angular数字 ”(&#FF11;是1)时,你会注意到这一点)。 保持XML的可读性是西西弗斯的任务。
我build议不要试图在XML中进行文本编码和转义。 但不要让这阻止你尝试; 只要记住当它咬你(而且会)。
也就是说,如果你只使用UTF-8,为了使事情更具可读性,你可以考虑这个策略:
- 如果文本包含“<”,“>”或“&”,则将其包装在
<![CDATA[ ... ]]>
- 如果文本不包含这三个字符,请不要弯曲。
我在SQL编辑器中使用它,它允许开发人员将SQL从第三方SQL工具剪切并粘贴到XML中,而无需担心转义。 这是有效的,因为在我们的例子中,SQL不能包含元音变音,所以我很安全。
要转义XML字符,最简单的方法是使用Apache Commons Lang项目,JAR可以从http://commons.apache.org/lang/下载。;
这个类是这样的:org.apache.commons.lang3.StringEscapeUtils;
它有一个名为“escapeXml”的方法,它将返回一个适当的转义string。
虽然我原则上同意Jon Skeet,但有时候我没有select使用外部XML库。 而且我发现在Java中包含的标准XML库中没有提供这两个函数来转义简单值(属性或标记,而不是完整文档)。
因此,根据我在这里和其他地方发布的不同答案,我已经创build了解决scheme(没有任何工作作为简单的复制/粘贴):
public final static String ESCAPE_CHARS = "<>&\"\'"; public final static List<String> ESCAPE_STRINGS = Collections.unmodifiableList(Arrays.asList(new String[] { "<" , ">" , "&" , """ , "'" })); private static String UNICODE_LOW = "" + ((char)0x20); //space private static String UNICODE_HIGH = "" + ((char)0x7f); //should only use 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 { stringBuilder.append("&#" + ((int)character.charAt(0)) + ";"); modified = true; } } } if (modified) { result = stringBuilder.toString(); } } return result; }
以上提供了几个不同的东西:
- 避免使用基于字符的逻辑,直到它绝对必须 – 提高Unicode兼容性
- 试图尽可能有效率的概率是第二个“如果”条件可能是最常用的途径
- 是一个纯粹的function; 即是线程安全的
- 通过只返回StringBuilder的内容来优化垃圾收集器,如果事实上发生了变化 – 否则返回原始string
在某些时候,我会把这个函数的反转写成uncanesped()。 我今天没有时间这样做。 当我这样做的时候,我会用代码来更新这个答案。 🙂
public String escapeXml(String s) { return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'"); }
对于那些寻求最快写入解决scheme的人:使用来自apache commons-lang的方法 :
-
StringEscapeUtils.escapeXml10()
for xml 1.0 -
StringEscapeUtils.escapeXml11()
for xml 1.1 -
StringEscapeUtils.escapeXml()
现在已被弃用,但在过去通常使用
请记住包含依赖关系:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.5</version> <!--check current version! --> </dependency>
这是一个简单的解决scheme,也非常适合编码重音字符!
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!
使用JAXP并忘记文本处理,它将自动完成。
尝试使用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());