4

XML の作成中にエラーが発生しました

メッセージ 6841、レベル 16、状態 1、行 26 FOR XML は、XML で許可されていない文字 (0x000C) が含まれているため、ノード '値' のデータをシリアル化できませんでした。FOR XML を使用してこのデータを取得するには、バイナリ、varbinary、またはイメージ データ型に変換し、BINARY BASE64 ディレクティブを使用します。

TSQLでそれを修正する方法を考え出した

私の質問はそれを防ぐ方法です

このデータは .NET C# を介してロードされます
既に次のようなクリーンアップを行っています:
- 先頭と末尾のスペースを削除します
- 複数のスペースを 1 つのスペースに連結します

XML で壊れる文字は何ですか?

.NET C# でこれらの文字を特定して削除する方法は?
データが SQL に入る前の入力時。

XML は TSQL FOR XML で生成されます (.NET 経由ではありません)。

このリンクを見つけまし た XML で有効な文字

次のコード ポイント範囲の Unicode コード ポイントは、XML 1.1 ドキュメントで常に有効です。 all) BMP 内の非文字 (サロゲート、U+FFFE および U+FFFF は禁止されています)。U+10000–U+10FFFF: これには、非文字を含む補助平面のすべてのコード ポイントが含まれます。

U+0001–U+D7FF をテストする方法がわかりません。

答えは、質問以上のものです。
質問で述べたように、私はすでに他の入力フィルタリングを実行していました。
xmlを追加したかっただけです。
実際のアプリでは、このユーザー データには制御文字が含まれていないため、すべての制御文字が除外されます。
win1252 の部分は int SQL char (バイト) に格納されたデータに合わせます。

私のFOR XMLを壊していたものは1.1で許可されているので、1.0の文字セットに行きました。
また、.NET では char が Int16 であるため、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;
    }
}
4

2 に答える 2