XmlReader在UTF-8 BOM上中断

aro*_*eer 7 c# byte-order-mark xmlreader utf-8

我的应用程序中有以下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));
    }
Run Code Online (Sandbox Code Playgroud)

我用它来解析发送到我的WCF服务的字符串到XML文档,用于自定义反序列化.

当我读入文件并通过网络发送它们时(请求),它工作正常; 我已经确认没有发送BOM.在我的请求处理程序中,我正在序列化响应对象并将其作为字符串发送回来.序列化过程将UTF-8 BOM添加到字符串的前面,这会导致在解析响应时中断相同的代码.

System.Xml.XmlException : Data at the root level is invalid. Line 1, position 1.
Run Code Online (Sandbox Code Playgroud)

在过去一小时左右的研究中,似乎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;
}
Run Code Online (Sandbox Code Playgroud)

如果只是xml错误地包含BOM的问题,那么我将切换到

var responseXml = new UTF8Encoding(false).GetString(bytes);
Run Code Online (Sandbox Code Playgroud)

但我的研究表明,实际的XML字符串中的BOM是非法的,这一点并不清楚; 请参阅例如c#从字节数组中检测xml编码?

jon*_*onp 9

在我的请求处理程序中,我正在序列化响应对象并将其作为字符串发送回来.序列化过程增加了一个UTF-8 BOM到串,这将导致相同的代码来破坏解析响应时的前部.

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

你应该做的是提供一个UTF8Encoding通过创建的实例UTF8Encoding(布尔)构造函数来禁用生成BOM,并且通过这个Encoding实例无论你使用的是产生的中间字符串的方法.


Luc*_*ero 6

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();
}
Run Code Online (Sandbox Code Playgroud)