Pregunta

tengo el siguiente código XML de análisis en mi aplicación:

    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));
    }

Lo estoy usando para analizar cadenas enviados a mi servicio WCF en documentos XML, para la deserialización personalizado.

Funciona bien cuando leo en los archivos y enviarlos a través del cable (la solicitud); He verificado que la lista de materiales no se envía a través. En mi controlador de solicitudes estoy serializar un objeto de respuesta y enviarla de nuevo como una cadena. El proceso de serialización añade una lista de materiales UTF-8 a la parte delantera de la cadena, lo que hace que el mismo código para romper al analizar la respuesta.

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

En la investigación que he hecho durante la última hora o así, parece que XmlReader debe respetar la lista de materiales. Si quito manualmente la lista de materiales desde el frente de la cadena, la respuesta XML analiza bien.

Me estoy perdiendo algo obvio, o al menos algo insidiosa?

editar Aquí está el código de serialización que estoy usando para devolver la respuesta:

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;
}

Si es sólo una cuestión de la forma incorrecta XML que contiene la lista de materiales, entonces voy a cambiar a

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

, pero no estaba claro en absoluto de mi investigación que la lista de materiales era ilegal en la cadena XML real; véase, por ejemplo c # xml Detección de codificación de matriz de bytes?

¿Fue útil?

Solución

La cadena XML debe no (!) Contener la lista de materiales, la lista de materiales sólo se permite en datos de bytes (por ejemplo, corrientes), que está codificado con UTF-8. Esto se debe a la representación de cadena no está codificado, pero ya es una secuencia de caracteres Unicode.

Por lo tanto parece que cargue el mal cadena, que es de código que desafortunadamente no proporcionó.

Editar

Gracias por publicar el código de serialización.

No se debe escribir los datos en un MemoryStream, sino más bien a un StringWriter que luego se puede convertir en una cadena con ToString. Dado que esto evita que pasa a través de una representación de bytes que no sólo es más rápido, pero también evita este tipo de problemas.

Algo como esto:

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();
}

Otros consejos

  

En mi controlador de solicitudes estoy serializar un objeto de respuesta y enviarla de nuevo como una cadena. El proceso de serialización añade una lista de materiales UTF-8 a la parte delantera de la cadena, lo que hace que el mismo código para romper al analizar la respuesta.

Así que usted quiere evitar que la lista de materiales que se agreguen como parte de su proceso de serialización. Por desgracia, no proporciona lo que su lógica es la serialización.

Lo que debe hacer es proporcionar una UTF8Encoding instancia creada a través de la UTF8Encoding (bool) constructor en generación disable de la lista de materiales , y pasar esta instancia Encoding a cualquier métodos que está utilizando, que están generando la cadena intermedia.

La lista de materiales no debe estar en la cadena en el primer lugar.
Listas de materiales se utilizan para detectar la codificación de una matriz de bytes en bruto; tienen nada que hacer en una cadena real.

Lo que hace la cadena viene?
Probablemente estás leyendo con la codificación incorrecta.

Cuerdas en C # se codifican como UTF-16, por lo que la lista de materiales sería un error. Como regla general, siempre codificación XML para matrices de bytes y decodificarlo de matrices de bytes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top