创建 XML 时出错
消息 6841,级别 16,状态 1,第 26 行 FOR XML 无法序列化节点“值”的数据,因为它包含 XML 中不允许的字符 (0x000C)。要使用 FOR XML 检索此数据,请将其转换为二进制、varbinary 或图像数据类型并使用 BINARY BASE64 指令。
想出了如何用 TSQL 解决这个问题
我的问题是如何预防
该数据是通过
.NET C# 加载
的
什么字符会破坏 FOR XML?
如何在 .NET C# 中识别和删除这些字符?
在数据甚至进入 SQL 之前的输入。
XML 是使用 TSQL FOR XML 生成的(不是通过 .NET)。
找到此链接 XML 中的有效字符
以下代码点范围内的 Unicode 代码点在 XML 1.1 文档中始终有效:[2] U+0001–U+D7FF、U+E000–U+FFFD:这包括大多数 C0 和 C1 控制字符,但不包括一些(不是all) BMP 中的非字符(禁止使用代理、U+FFFE 和 U+FFFF);U+10000–U+10FFFF:这包括辅助平面中的所有代码点,包括非字符。
我不知道如何测试 U+0001–U+D7FF。
答案比问题多。
如问题中所述,我已经在执行其他输入过滤。
我只是想添加xml。
在实际应用中,将过滤掉所有控制字符,因为此用户数据不应包含任何控制字符。
win1252部分是为了对齐存储的int SQL char(byte)的数据。
使用 1.0 字符集,因为 1.1 中允许破坏我的 FOR XML。
也仅适用于 Int16,因为 char 在 .NET 中是 Int16。
public static string RemoveDiatricsXMLsafe(string unicodeString, bool toLower, bool toWin1252)
{
// cleary could just create the Regex and validXMLsingle once in the ctor
unicodeString = Regex.Replace(unicodeString, @"\s{2,}", " ");
//U+0009, U+000A, U+000D: these are the only C0 controls accepted in XML 1.0;
//U+0020–U+D7FF, U+E000–U+FFFD
Int16[] validXMLsingle = new Int16[4];
validXMLsingle[0] = Int16.Parse("0020", System.Globalization.NumberStyles.HexNumber);
validXMLsingle[1] = Int16.Parse("0009", System.Globalization.NumberStyles.HexNumber);
validXMLsingle[2] = Int16.Parse("000A", System.Globalization.NumberStyles.HexNumber);
validXMLsingle[3] = Int16.Parse("000D", System.Globalization.NumberStyles.HexNumber);
unicodeString = unicodeString.Trim();
Int16 u16;
StringBuilder sb = new StringBuilder();
bool validXML = false;
if (toLower) unicodeString = unicodeString.ToLowerInvariant();
foreach (char c in unicodeString.Normalize(NormalizationForm.FormD)) // : NormalizationForm.FormKD) breaks
{
switch (CharUnicodeInfo.GetUnicodeCategory(c))
{
case UnicodeCategory.NonSpacingMark:
case UnicodeCategory.SpacingCombiningMark:
case UnicodeCategory.EnclosingMark:
//do nothing
break;
default:
u16 = (Int16)c;
validXML = false;
if (u16 >= validXMLsingle[0]) validXML = true;
else if (u16 == validXMLsingle[1]) validXML = true;
else if (u16 == validXMLsingle[2]) validXML = true;
else if (u16 == validXMLsingle[3]) validXML = true;
if (validXML) sb.Append(c);
break;
}
}
if (!toWin1252)
{
return sb.ToString();
}
else
{
Encoding win1252 = Encoding.GetEncoding("Windows-1252");
Encoding unicode = Encoding.Unicode;
// Convert the string into a byte array.
byte[] unicodeBytes = unicode.GetBytes(sb.ToString());
// Perform the conversion from one encoding to the other.
byte[] win1252Bytes = Encoding.Convert(unicode, win1252, unicodeBytes);
// Convert the new byte[] into a char[] and then into a string.
char[] win1252Chars = new char[win1252.GetCharCount(win1252Bytes, 0, win1252Bytes.Length)];
win1252.GetChars(win1252Bytes, 0, win1252Bytes.Length, win1252Chars, 0);
return new string(win1252Chars);
//string win1252String = new string(win1252Chars);
//return win1252String;
}
}