我有一个包含无效 XML 字符的字符串。在解析字符串之前如何转义(或删除)无效的 XML 字符?
作为删除无效 XML 字符的方法,我建议您使用 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 字符的方法,我建议您使用 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;
}
}
更新: 应当指出的是,编码操作产生的字符串的长度大于或等于源字符串的长度。当您将编码字符串存储在数据库中具有长度限制的字符串列中并验证应用程序中的源字符串长度以适应数据列限制时,这可能很重要。
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,只需使用框架提供的类来创建xml。你不必费心逃跑什么的。
Console.Write(new XElement("Data", "< > &"));
将会输出
<Data>< > &</Data>
如果您需要读取格式错误的 XML 文件,不要 使用正则表达式。相反,请使用 Html Agility Pack。
Irishman 提供的RemoveInvalidXmlChars 方法不支持代理字符。要测试它,请使用以下示例:
static void Main()
{
const string content = "\v\U00010330";
string newContent = RemoveInvalidXmlChars(content);
Console.WriteLine(newContent);
}
这会返回一个空字符串,但它不应该!它应该返回“\U00010330”,因为字符 U+10330 是有效的 XML 字符。
为了支持代理字符,我建议使用以下方法:
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的优化版本,它不会在每次调用时创建一个新数组,从而不必要地给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();
}
如果您只是转义 XML 标记内部使用的字符串的无效 XML 字符,您可以执行如下简单操作。
这在您不使用 XML 库时有效。
public string EscapeXMLCharacters (string target)
{
return
target
.Replace("&", "&")
.Replace("<", "<")
.Replace(">", ">")
.Replace("\"", """)
.Replace("'", "'");
//suggested by nimblebit to avoid double replace situations
.Replace("&amp;", "&")
}
然后你可以这样称呼它:
public string GetXMLBody(string content)
{
return @"<input>" + EscapeXMLCharacters(content) + "</input>";
}
// Replace invalid characters with empty strings.
Regex.Replace(inputString, @"[^\w\.@-]", "");
正则表达式模式 [^\w.@-] 匹配除单词字符、句点、@ 符号或连字符之外的任何字符。单词字符是任何字母、十进制数字或标点符号连接符(例如下划线)。与此模式匹配的任何字符都将替换为 String.Empty,它是替换模式定义的字符串。要允许用户输入其他字符,请将这些字符添加到正则表达式模式中的字符类中。例如,正则表达式模式 [^\w.@-\%] 还允许在输入字符串中使用百分比符号和反斜杠。
Regex.Replace(inputString, @"[!@#$%_]", "");
也参考这个:
这是一个从指定 XML 字符串中删除字符的函数:
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;
}
}
}
string XMLWriteStringWithoutIllegalCharacters(string UnfilteredString)
{
if (UnfilteredString == null)
return string.Empty;
return XmlConvert.EncodeName(UnfilteredString);
}
string XMLReadStringWithoutIllegalCharacters(string FilteredString)
{
if (UnfilteredString == null)
return string.Empty;
return XmlConvert.DecodeName(UnfilteredString);
}
这个简单的方法用相同的值替换无效字符,但在 XML 上下文中接受。
要写入字符串,请使用 XMLWriteStringWithoutIllegalCharacters(string UnfilteredString)。
要读取字符串,请使用 XMLReadStringWithoutIllegalCharacters(string FilteredString)。