在C#中转义无效的XML字符
我有一个string包含无效的XML字符。 在parsingstring之前,如何转义(或删除)无效的XML字符?
作为删除无效XML字符的方法,我build议您使用XmlConvert.IsXmlChar方法。 它是从.NET Framework 4开始添加的,也是在Silverlight中提供的。 这是一个小样本:
void Main() { string content = "\v\f\0"; Console.WriteLine(IsValidXmlString(content)); // False content = RemoveInvalidXmlChars(content); Console.WriteLine(IsValidXmlString(content)); // True } static string RemoveInvalidXmlChars(string text) { var validXmlChars = text.Where(ch => XmlConvert.IsXmlChar(ch)).ToArray(); return new string(validXmlChars); } static bool IsValidXmlString(string text) { try { XmlConvert.VerifyXmlChars(text); return true; } catch { return false; } }
而作为转义无效的XML字符的方式,我build议您使用XmlConvert.EncodeName方法。 这是一个小样本:
void Main() { const string content = "\v\f\0"; Console.WriteLine(IsValidXmlString(content)); // False string encoded = XmlConvert.EncodeName(content); Console.WriteLine(IsValidXmlString(encoded)); // True string decoded = XmlConvert.DecodeName(encoded); Console.WriteLine(content == decoded); // True } static bool IsValidXmlString(string text) { try { XmlConvert.VerifyXmlChars(text); return true; } catch { return false; } }
更新:应该提到编码操作产生一个长度大于或等于源string长度的string。 将编码string存储在数据库中的长度受限的string列中,并在您的应用中validation源string长度以适合数据列的限制时,这一点很重要。
使用SecurityElement.Escape
using System; using System.Security; class Sample { static void Main() { string text = "Escape characters : < > & \" \'"; string xmlText = SecurityElement.Escape(text); //output: //Escape characters : < > & " ' Console.WriteLine(xmlText); } }
如果您正在编写xml,只需使用框架提供的类来创buildxml即可。 你不必费心逃跑或任何事情。
Console.Write(new XElement("Data", "< > &"));
会输出
<Data>< > &</Data>
如果您需要阅读格式错误的XML文件, 请不要 使用正则expression式。 而是使用Html Agility Pack 。
Irishman提供的RemoveInvalidXmlChars方法不支持代理字符。 要testing它,请使用以下示例:
static void Main() { const string content = "\v\U00010330"; string newContent = RemoveInvalidXmlChars(content); Console.WriteLine(newContent); }
这将返回一个空string,但它不应该! 它应该返回“\ U00010330”,因为字符U + 10330是一个有效的XML字符。
为了支持代理字符,我build议使用以下方法:
public static string RemoveInvalidXmlChars(string text) { if (string.IsNullOrEmpty(text)) return text; int length = text.Length; StringBuilder stringBuilder = new StringBuilder(length); for (int i = 0; i < length; ++i) { if (XmlConvert.IsXmlChar(text[i])) { stringBuilder.Append(text[i]); } else if (i + 1 < length && XmlConvert.IsXmlSurrogatePair(text[i + 1], text[i])) { stringBuilder.Append(text[i]); stringBuilder.Append(text[i + 1]); ++i; } } return stringBuilder.ToString(); }
这里是上述方法RemoveInvalidXmlChars的优化版本,它不会在每次调用时创build一个新的数组,因此强调GC是非常重要的:
public static string RemoveInvalidXmlChars(string text) { if (text == null) return text; if (text.Length == 0) return text; // a bit complicated, but avoids memory usage if not necessary StringBuilder result = null; for (int i = 0; i < text.Length; i++) { var ch = text[i]; if (XmlConvert.IsXmlChar(ch)) { result?.Append(ch); } else { if (result == null) { result = new StringBuilder(); result.Append(text.Substring(0, i)); } } } if (result == null) return text; // no invalid xml chars detected - return original text else return result.ToString(); }
// Replace invalid characters with empty strings. Regex.Replace(inputString, @"[^\w\.@-]", "");
正则expression式模式[^ \ w。@ – ]匹配任何不是单词字符,句点,@符号或连字符的字符。 单词字符是任何字母,十进制数字或标点连接符(如下划线)。 与此模式相匹配的任何字符都被replace为replace模式定义的stringString.Empty。 要允许用户input中的其他字符,请将这些字符添加到正则expression式模式中的字符类中。 例如,正则expression式模式[^ \ w。@ – \%]也允许在inputstring中使用百分比符号和反斜杠。
Regex.Replace(inputString, @"[!@#$%_]", "");
也请参考:
从XML名称标记中删除无效字符 – 正则expression式C#
这是一个从指定的XMLstring中删除字符的函数:
using System; using System.IO; using System.Text; using System.Text.RegularExpressions; namespace XMLUtils { class Standards { /// <summary> /// Strips non-printable ascii characters /// Refer to http://www.w3.org/TR/xml11/#charsets for XML 1.1 /// Refer to http://www.w3.org/TR/2006/REC-xml-20060816/#charsets for XML 1.0 /// </summary> /// <param name="content">contents</param> /// <param name="XMLVersion">XML Specification to use. Can be 1.0 or 1.1</param> private void StripIllegalXMLChars(string tmpContents, string XMLVersion) { string pattern = String.Empty; switch (XMLVersion) { case "1.0": pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|7F|8[0-46-9A-F]9[0-9A-F])"; break; case "1.1": pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|[19][0-9A-F]|7F|8[0-46-9A-F]|0?[1-8BCEF])"; break; default: throw new Exception("Error: Invalid XML Version!"); } Regex regex = new Regex(pattern, RegexOptions.IgnoreCase); if (regex.IsMatch(tmpContents)) { tmpContents = regex.Replace(tmpContents, String.Empty); } tmpContents = string.Empty; } } }