XmlReader прерывается на спецификации UTF-8 - PullRequest
7 голосов
/ 23 июня 2010

У меня в приложении есть следующий код синтаксического анализа 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 для пользовательской десериализации.

Этоотлично работает, когда я читаю файлы и отправляю их по проводам (запрос);Я проверил, что спецификация не пересылается.В моем обработчике запросов я сериализую объект ответа и отправляю его обратно в виде строки.Процесс сериализации добавляет спецификацию UTF-8 в начало строки, что приводит к разрыву того же кода при анализе ответа.

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

В исследовании, которое я провел за последний час или около тогоПохоже, что XmlReader должен соблюдать спецификацию.Если я вручную удаляю спецификацию в начале строки, 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 неправильно содержит спецификацию, то я переключусь на

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

, но из моих исследований вообще не было ясно, что эта спецификация была незаконной вактуальная строка XML;см. например c # Обнаружить кодировку xml из массива байтов?

Ответы [ 4 ]

9 голосов
/ 23 июня 2010

В моем обработчике запросов я сериализую объект ответа и отправляю его обратно в виде строки. Процесс сериализации добавляет спецификацию UTF-8 в начало строки, что приводит к разрыву того же кода при анализе ответа.

Таким образом, вы хотите предотвратить добавление спецификации как часть процесса сериализации. К сожалению, вы не предоставляете логику сериализации.

Вам нужно предоставить экземпляр UTF8Encoding , созданный с помощью конструктора UTF8Encoding (bool) , чтобы отключить создание спецификации и передать этот экземпляр Encoding любым используемым вами методам. Используете которые генерируют вашу промежуточную строку.

6 голосов
/ 23 июня 2010

Строка xml не должна (!) Содержать спецификацию, эта спецификация допускается только в байтовых данных (например, в потоках), которые кодируются с помощью UTF-8. Это потому, что строковое представление не закодировано, но уже является последовательностью символов Юникода.

Поэтому кажется, что вы неправильно загрузили строку, что в коде, который вы, к сожалению, не предоставили.

Edit:

Спасибо за публикацию кода сериализации.

Вы должны записывать данные не в 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();
}
0 голосов
/ 23 июня 2010

Строки в C # кодируются как UTF-16, поэтому спецификация будет неправильной.Как правило, всегда кодируйте XML в байтовые массивы и декодируйте его из байтовых массивов.

0 голосов
/ 23 июня 2010

Во-первых, спецификация не должна быть в строке.
Спецификации используются для определения кодировки необработанного массива байтов;они не имеют никакого отношения к фактической строке.

Откуда взялась строка?
Возможно, вы читаете ее с неправильной кодировкой.

...