【问题标题】:How to prevent illegal characters to appear in my XML when retrieving it from SQL Server从 SQL Server 检索 XML 时如何防止非法字符出现在我的 XML 中
【发布时间】:2010-08-24 12:54:35
【问题描述】:

有时我的类中属性的字符串值会变得奇怪。它们包含非法字符,并显示如下(带框):

123[]45[]6789

我假设这些是非法/无法识别的字符。我将所有对象序列化为 XML,然后通过 Web 服务上传它们。当我再次检索它们时,一些字符被替换为奇怪的字符。使用 Word 键入的连字符和破折号最常发生这种情况。这是它的原因吗?

无论如何我可以通过正则表达式或其他方式检查字符串是否包含任何这些无法识别的字符?

【问题讨论】:

  • 你是什么意思'显示这样'?显示在哪里 - 调试时?
  • @cofiem 假设我“下载报告”并将值放回文本框中,它们会像上面那样出现(有时,并非总是如此)。
  • 我认为他的意思是他的编码不能识别字符,所以它们显示为框。
  • @snow:您能否更具体地了解您下载报告的情况?似乎在你得到你的字符串之前涉及一个完整的过程,并且需要检查链中的每个链接。
  • @Abel 我们在 SQL Server 中存储一个 xml 字符串。用户将通过 Web 服务下载该 XML 字符串并将对象反序列化回其原始状态。这在很大程度上是“下载”。

标签: c# regex web-services xml-serialization illegal-characters


【解决方案1】:

首先要记住的是,没有“特殊字符”或“非法字符”之类的东西。在某些情况下有特殊字符,也有非字符,但一般没有“特殊字符”或“非法字符”。

你在这里拥有的是:

  1. 您的字体没有字形的完全正常的字符。
  2. 完全正常的不可打印字符(例如控制字符)。
  3. 调试器的工作原理。

首先要找出那个字符是什么。找到字符的整数值,然后查找。

需要注意的一个重要问题是 U+FFFD (�),因为它有时在解码器收到一堆在其尝试使用的编码上下文中没有意义的字节时使用(例如,0x80 后跟by 0x20 在 UTF-8 中没有任何意义,一种可能的响应是使用 U+FFFD 作为“这里有一些奇怪的东西”标记,其他可能的响应是抛出错误,并且也会默默地忽略错误或试图猜测意图最后两个会带来安全问题)。

一旦你弄清楚了这一点,你就可以开始推理它为什么会进入那里,如果它不是预期的。可能是一个编码问题(写入的字符集不是读入的字符集)?它是否真的打算在那里?会不会是别的东西?在您获得有关该错误的更多信息之前,您无法开始回答这个问题。

最后,是如何处理它的问题。希望从您在上述研究中找到的答案中可以明显看出这一点。答案可能是“没什么,没关系”,可能是简单的,也可能是困难的。还不能说。

不要只使用正则表达式进行过滤。也许这将是正确的解决方案,但你还不知道,所以也许你正在让更深层次的错误比现在更难找到,或者破坏了完美的数据。

【讨论】:

  • 好吧,数据库中的 XML 读取为“123-45-6789”,但是当我将 XML 反序列化回客户端上的对象时,它读取为“123[]45[]6789”,是这一切都回到编码?
  • 可能。 (int)"123[]45[]6789"[3] 这里的值是多少?这会告诉我们很多。就此而言,您确定第一个字符串中的第四个字符是 - 而不是 -、-、-、- 或 - (实际上, - 会比 - 更好的排版,尽管在机器可读的上下文中没有那么有用)。这也会告诉我们一些事情。
  • 好吧,当我在调试器中运行它时 ?Char.GetNumericValue("12‑34‑5678", 2) 它返回 -1.0
  • 不,第三个字符的实际代码点,如果直接将其转换为 int,则会得到。
  • 那是“不间断的连字符”。这是一个编码问题。
【解决方案2】:

我个人认为使用正则表达式检查这些字符不是正确的解决方案。如果您不存储这些字符,那么显然存在某种编码问题。

验证 XML 文档本身是使用正确的编码存储的,以支持您需要存储的字符。然后验证您在读取文件时是否使用与文档相同的编码,即如果您的 XML 文档存储为 UTF-8,那么您需要确保在读取时将其编码为 UTF-8。

【讨论】:

    【解决方案3】:

    深入了解字符本身,实际的 char 值是多少?

    当一个字符显示为正方形时,这意味着您无法直观地表示它。这可能是因为它是一个非可视字符,或者它不在您当前的字符集范围内。

    编辑,不

    在您的示例中,我冒昧地猜测您看到的是嵌入的换行符。

    【讨论】:

    • 看看这个 char 实体表。您的问题可能是 mdash - 较长的破折号。编码通常会导致问题。 en.wikipedia.org/wiki/…
    【解决方案4】:

    定义允许的字符并阻止其他所有字符,即:

    // only lowercase letters and digits
    if(Regex.IsMatch(yourString, @"^[a-z0-9]*$"))
    {
        // allowed
    }
    

    但我认为您的问题可能出在其他地方,因为您说它来自序列化(有效)字符串然后反序列化(无效)字符串。可能是您使用默认序列化并且您没有为您的类应用正确的ISerializable 实现(或正确使用Serializable 属性),导致属性或字段被序列化,而您不希望成为序列化。

    PS:其他人提到了编码问题,这是一个可能的原因,可能意味着您根本无法读取数据。关于编码,有一个简单的规则:在任何地方(流、数据库、xml)都使用相同的编码并且要具体。如果不是,则使用默认编码,不同系统可能不同。


    编辑:可能的解决方案

    根据新信息(请参阅原始问题下的线程),很明显该问题与编码有关。 OP 提到它以破折号出现,在某些花哨的编辑环境中使用时,通常会用漂亮的破折号代替,例如“—”(—)。由于似乎在如何修复 SQL Server 以接受正确的编码字符串方面存在一些不确定性,您也可以在 XML 中解决这个问题。

    创建 XML 时,只需将编码更改为最基本的可能 (US-ASCII)。这将自动强制 XML 编写器使用正确的数字实体。当您反序列化时,这将在您的字符串中正确解析,无需多言。大致如下:

    Stream stream = new MemoryStream();
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Encoding = Encoding.ASCII;
    XmlWriter writer = XmlWriter.Create(stream, settings);
    // make sure to output the xml-prolog header
    

    但请注意使用StringBuilderStringWriter,因为它被固定为使用UTF-16,并且XmlWriter 将始终使用该编码more info on that issue at my blog 写入,这与SQL Server 不兼容。

    注意:当使用 ASCII 编码时,任何高于0x7F 的字符都会被编码。所以,é 看起来像&#xE9,破折号可能看起来像&#x2014,但这意味着相同,您不必担心。每个支持 XML 的工具都会正确解释这个输入。

    注意 2:您要更改 XML 编写方式的位置是您所说的 Web 服务,它接收 XML,然后将其存储到 SQL Server 数据库中。在存储到 SQL Server 之前,必须应用更改。在链条的前面是没用的。

    【讨论】:

    • 我对您的回答投了反对票,因为我认为 Regex 不是正确的解决方案。我注意到您更改了答案,但是,在您编辑问题之前,我无法删除反对票:)
    • @James:我同意正则表达式是一种解决方法,而不是解决方案,甚至可能根本没有帮助。感谢您的评论。我实际上只是修复了那个非常正则表达式;-)
    【解决方案5】:
    public static T DeserializeFromXml<T>(string xml)
            {
                T result;
                XmlSerializerFactory serializerFactory = new XmlSerializerFactory();
                XmlSerializer serializer =serializerFactory.CreateSerializer(typeof(T));
    
                using (StringReader sr3 = new StringReader(xml))
                {
                    XmlReaderSettings settings = new XmlReaderSettings()
                    {
                        CheckCharacters = false // default value is true;
                    };
    
                    using (XmlReader xr3 = XmlTextReader.Create(sr3, settings))
                    {
                        result = (T)serializer.Deserialize(xr3);
                    }
                }
    
                return result;
            }
    

    【讨论】:

    • 请添加一些解释性文字。纯代码答案没那么有用
    • 你能解释一下你在这里做什么吗?
    猜你喜欢
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    相关资源
    最近更新 更多