代码之家  ›  专栏  ›  技术社区  ›  Matt Mills

UTF-8物料清单上的XmlReader中断

  •  7
  • Matt Mills  · 技术社区  · 14 年前

    我的应用程序中有以下XML分析代码:

        public static XElement Parse(string xml, string xsdFilename)
        {
            var readerSettings = new XmlReaderSettings
            {
                ValidationType = ValidationType.Schema,
                Schemas = new XmlSchemaSet()
            };
            readerSettings.Schemas.Add(null, xsdFilename);
            readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
            readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
            readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
            readerSettings.ValidationEventHandler +=
                (o, e) => { throw new Exception("The provided XML does not validate against the request's schema."); };
    
            var readerContext = new XmlParserContext(null, null, null, XmlSpace.Default, Encoding.UTF8);
    
            return XElement.Load(XmlReader.Create(new StringReader(xml), readerSettings, readerContext));
        }
    

    我正在使用它将发送到我的WCF服务的字符串解析为XML文档,以便自定义反序列化。

    当我读取文件并通过网络发送它们(请求)时,它工作得很好;我已经验证了BOM没有被发送过。在我的请求处理程序中,我正在序列化一个响应对象,并将其作为字符串发送回来。序列化过程在字符串的前面添加了一个utf-8bom,这会导致解析响应时相同的代码中断。

    System.Xml.XmlException : Data at the root level is invalid. Line 1, position 1.
    

    在我过去一小时左右所做的研究中,似乎xmlReader应该尊重这个BOM。如果我手动从字符串前面移除BOM,那么响应XML会很好地进行解析。

    我是在错过一些明显的东西,还是至少是一些阴险的东西?

    编辑: 下面是我用来返回响应的序列化代码:

    private static string SerializeResponse(Response response)
    {
        var output = new MemoryStream();
        var writer = XmlWriter.Create(output);
        new XmlSerializer(typeof(Response)).Serialize(writer, response);
        var bytes = output.ToArray();
        var responseXml = Encoding.UTF8.GetString(bytes);
        return responseXml;
    }
    

    如果只是XML错误地包含了BOM,那么我将切换到

    var responseXml = new UTF8Encoding(false).GetString(bytes);
    

    但从我的研究中还不清楚,BOM在实际的XML字符串中是非法的;请参见例如。 c# Detect xml encoding from Byte Array?

    4 回复  |  直到 14 年前
        1
  •  6
  •   Lucero    14 年前

    XML字符串不能为(!)包含bom,bom只允许在字节数据(例如流)中使用utf-8编码。这是因为字符串表示形式不是编码的,而是已经是一个Unicode字符序列。

    因此,您似乎错误地加载了字符串,这是您不幸没有提供的代码。

    编辑:

    感谢您发布序列化代码。

    您不应该将数据写入memoryStream,而应该写入一个StringWriter,然后可以用ToString将其转换为字符串。由于这避免了通过字节表示,因此不仅速度更快,而且还避免了此类问题。

    像这样:

    private static string SerializeResponse(Response response)
    {
        var output = new StringWriter();
        var writer = XmlWriter.Create(output);
        new XmlSerializer(typeof(Response)).Serialize(writer, response);
        return output.ToString();
    }
    
        2
  •  9
  •   jonp    14 年前

    在我的请求处理程序中,我正在序列化一个响应对象,并将其作为字符串发送回来。序列化过程在字符串的前面添加了一个utf-8bom,这会导致解析响应时相同的代码中断。

    因此,您希望防止在序列化过程中添加BOM。不幸的是,您没有提供序列化逻辑是什么。

    你应该做的是提供 UTF8Encoding 通过创建实例 UTF8Encoding(bool) 用于禁用生成物料清单的构造函数,并传递此 Encoding 实例到正在使用的生成中间字符串的方法。

        3
  •  0
  •   SLaks    14 年前

    物料清单一开始不应该在字符串中。
    BOM用于检测原始字节数组的编码;它们没有实际字符串中的业务。

    这根绳子是什么?
    你可能是用错误的编码读的。

        4
  •  0
  •   Stephen Cleary    14 年前

    C中的字符串编码为UTF-16,因此BOM将是错误的。作为一般规则,总是将XML编码为字节数组,并从字节数组对其进行解码。