识别并删除将破坏FOR XML的字符

时间:2013-04-17 12:20:57

标签: .net xml tsql

创建XML

时出错
  

Msg 6841,Level 16,State 1,Line 26 FOR XML无法序列化   节点'value'的数据,因为它包含一个字符(0x000C)   XML中不允许使用。要使用FOR XML检索此数据,请将其转换   到二进制,varbinary或图像数据类型并使用BINARY BASE64   指令。

弄清楚如何使用TSQL解决这个问题

我的问题是如何防止它

此数据通过.NET C#加载 已经做了一些清理工作如下:
- 删除前导和尾随空格
- 将多个空格连接到单个空格

什么字符会破坏FOR XML?

如何在.NET C#中识别和删除这些字符? 在输入数据之前甚至进入SQL。

XML是使用TSQL FOR XML(不是通过.NET)生成的。

找到此链接 Valid characters in XML

  

以下代码点范围中的Unicode代码点始终是   在XML 1.1文档中有效:[2] U + 0001-U + D7FF,U + E000-U + FFFD:这个   包括大多数C0和C1控制字符,但不包括一些(不是   所有)BMP中的非字符(代理,U + FFFE和U + FFFF都是   禁止的); U + 10000-U + 10FFFF:这包括所有代码点   补充飞机,包括非人物。

我不知道如何测试U + 0001-U + D7FF。

答案不仅仅是问题 正如问题所述,我已经在进行其他输入过滤 我只想添加xml 在实际应用程序中将过滤掉所有控制字符,因为此用户数据不应具有任何控制字符 win1252部分是与存储在SQL char(byte)中的数据对齐。

在1.1中允许使用1.0字符集,因为我的FOR XML是允许的 也只适用于Int16,因为char是Int16 in .NET。

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;
    }
}

2 个答案:

答案 0 :(得分:1)

我猜是'0x000C' = '<'http://www.wimpyplayer.com/docs/howto/special_characters.html)。那么,在插入之前,您是否只需要将XML放入每个节点中的数据?

在此处回答:String escape into XML

public static string XmlEscape(string unescaped)
{
    XmlDocument doc = new XmlDocument();
    var node = doc.CreateElement("root");
    node.InnerText = unescaped;
    return node.InnerXml;
}

public static string XmlUnescape(string escaped)
{
    XmlDocument doc = new XmlDocument();
    var node = doc.CreateElement("root");
    node.InnerXml = escaped;
    return node.InnerText;
}

答案 1 :(得分:1)

在.Net方面,您应该能够使用正则表达式来判断您是否有一只奇怪的鸟:

var reg = new Regex("[^[\u0001-\ud7ff\ue000-\ufffd)]");
if(reg.IsMatch(...)
{
    // do what you want if you find something you don't want
}