【问题标题】:Identify and remove characters that will break FOR XML识别并删除会破坏 FOR XML 的字符
【发布时间】:2013-04-17 12:20:57
【问题描述】:

创建 XML 时出错

消息 6841,级别 16,状态 1,第 26 行 FOR XML 无法序列化 节点“值”的数据,因为它包含一个字符 (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: this 包括大多数 C0 和 C1 控制字符,但不包括一些(不 所有)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;
    }
}

【问题讨论】:

  • @ChrisGessler 该链接显示了一种删除无效字符的方法,但它无法识别哪些字符无效。
  • 4 票结束?它不是重复的。另一个问题没有确定要删除哪些字符。并且没有公认的答案。
  • 如果您的数据包含无效字符,则删除它们会损坏您的数据。所以不要删除它们。只需对整个字符串进行 base64 编码。

标签: .net xml tsql


【解决方案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
}

【讨论】:

  • 让我测试一下。对我来说有点意思。
  • 我采用了另一种方法,但这是对问题的有效答案。
【解决方案2】:

我猜是'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;
}

【讨论】:

  • XML 来自带有 FOR XML 的 TSQL 语句。 .NET 正在处理传入(而不是传出)的数据。
猜你喜欢
  • 2013-04-14
  • 2017-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-26
  • 2021-09-06
  • 1970-01-01
相关资源
最近更新 更多