用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 "&lt;A &amp; B &gt;" * .... (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("&lt;"); break; case '>': sb.append("&gt;"); break; case '\"': sb.append("&quot;"); break; case '&': sb.append("&amp;"); break; case '\'': sb.append("&apos;"); 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[] { "&lt;" , "&gt;" , "&amp;" , "&quot;" , "&apos;" })); 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; } 

以上提供了几个不同的东西:

  1. 避免使用基于字符的逻辑,直到它绝对必须 – 提高Unicode兼容性
  2. 试图尽可能有效率的概率是第二个“如果”条件可能是最常用的途径
  3. 是一个纯粹的function; 即是线程安全的
  4. 通过只返回StringBuilder的内容来优化垃圾收集器,如果事实上发生了变化 – 否则返回原始string

在某些时候,我会把这个函数的反转写成uncanesped()。 我今天没有时间这样做。 当我这样做的时候,我会用代码来更新这个答案。 🙂

 public String escapeXml(String s) { return s.replaceAll("&", "&amp;").replaceAll(">", "&gt;").replaceAll("<", "&lt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;"); } 

对于那些寻求最快写入解决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&#226;rry &#38; M&#244;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());