the - ¿Por qué falla C#XmlDocument.LoadXml(cadena) cuando se incluye un encabezado XML?
data at the root level is invalid line 1 position 1 loadxml c# (9)
Fondo
Aunque su pregunta tiene el conjunto de codificación como UTF-16, no tiene la cadena escapada correctamente, así que no estaba seguro si, de hecho, transpuso con precisión la cadena en su pregunta.
Me encontré con la misma excepción:
System.Xml.XmlException: los datos en el nivel raíz no son válidos. Línea 1, posición 1.
Sin embargo, mi código se veía así:
string xml = "<?xml version=/"1.0/" encoding=/"utf-8/" ?>/n<event>This is a Test</event>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
El problema
El problema es que las cadenas se almacenan internamente como UTF-16 en .NET, pero la codificación especificada en el encabezado del documento XML puede ser diferente. P.ej:
<?xml version="1.0" encoding="utf-8"?>
De la documentación de MSDN para Cadena here :
Cada carácter Unicode en una cadena está definido por un valor escalar Unicode, también llamado punto de código Unicode o el valor ordinal (numérico) del carácter Unicode. Cada punto de código se codifica utilizando la codificación UTF-16, y el valor numérico de cada elemento de la codificación se representa mediante un objeto Char.
Esto significa que cuando pasa XmlDocument.LoadXml () su cadena con un encabezado XML, debe decir que la codificación es UTF-16. De lo contrario, la codificación subyacente real no coincidirá con la codificación informada en el encabezado y dará lugar a que se genere una XmlException.
La solución
La solución para este problema es asegurarse de que la codificación utilizada en lo que pase el método Load o LoadXml coincida con lo que usted dice que está en el encabezado XML. En mi ejemplo anterior, cambie su encabezado XML para indicar UTF-16 o codifique la entrada en UTF-8 y use uno de los métodos XmlDocument.Load .
A continuación se muestra el código de ejemplo que demuestra cómo usar un MemoryStream para construir un XmlDocument utilizando una cadena que define un documento XML con codificación UTF-8 (pero, por supuesto, se almacena una cadena .NET UTF-16).
string xml = "<?xml version=/"1.0/" encoding=/"utf-8/" ?>/n<event>This is a Test</event>";
// Encode the XML string in a UTF-8 byte array
byte[] encodedString = Encoding.UTF8.GetBytes(xml);
// Put the byte array into a stream and rewind it to the beginning
MemoryStream ms = new MemoryStream(encodedString);
ms.Flush();
ms.Position = 0;
// Build the XmlDocument from the MemorySteam of UTF-8 encoded bytes
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(ms);
¿Alguien tiene alguna idea de por qué el siguiente ejemplo de código falla con XmlException? "Los datos en el nivel raíz no son válidos. Línea 1, posición 1."
var body = "<?xml version="1.0" encoding="utf-16"?><Report> ......"
XmlDocument bodyDoc = new XmlDocument();
bodyDoc.LoadXml(body);
Esto funcionó para mí:
var xdoc = new XmlDocument { XmlResolver = null };
xdoc.LoadXml(xmlFragment);
Esto realmente me salvó el día.
Escribí un método de extensión basado en la respuesta de Zach, también lo extendí para usar la codificación como parámetro, permitiendo que se usen diferentes codificaciones además de UTF-8, y envolví el MemoryStream en una declaración ''using''.
public static class XmlHelperExtentions
{
/// <summary>
/// Loads a string through .Load() instead of .LoadXml()
/// This prevents character encoding problems.
/// </summary>
/// <param name="xmlDocument"></param>
/// <param name="xmlString"></param>
public static void LoadString(this XmlDocument xmlDocument, string xmlString, Encoding encoding = null) {
if (encoding == null) {
encoding = Encoding.UTF8;
}
// Encode the XML string in a byte array
byte[] encodedString = encoding.GetBytes(xmlString);
// Put the byte array into a stream and rewind it to the beginning
using (var ms = new MemoryStream(encodedString)) {
ms.Flush();
ms.Position = 0;
// Build the XmlDocument from the MemorySteam of UTF-8 encoded bytes
xmlDocument.Load(ms);
}
}
}
Línea simple:
bodyDoc.LoadXml(new MemoryStream(Encoding.Unicode.GetBytes(body)));
Me lo imaginé. Lea la documentación de MSDN y dice usar .Load en lugar de LoadXml al leer cadenas. Descubrí que esto funciona el 100% del tiempo. Curiosamente, usar StringReader causa problemas. Creo que la razón principal es que esta es una cadena codificada en Unicode y que podría causar problemas porque StringReader es solo UTF-8.
MemoryStream stream = new MemoryStream();
byte[] data = body.PayloadEncoding.GetBytes(body.Payload);
stream.Write(data, 0, data.Length);
stream.Seek(0, SeekOrigin.Begin);
XmlTextReader reader = new XmlTextReader(stream);
// MSDN reccomends we use Load instead of LoadXml when using in memory XML payloads
bodyDoc.Load(reader);
Prueba esto:
XmlDocument bodyDoc = new XmlDocument();
bodyDoc.XMLResolver = null;
bodyDoc.Load(body);
Solución simple y efectiva: en lugar de usar el método LoadXml()
use el método Load()
Por ejemplo:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("sample.xml");
Tuve el mismo problema al cambiar de ruta absoluta a relativa para mi archivo xml. A continuación se resuelven tanto la carga como el uso de los problemas relativos de la ruta de origen. Usar un XmlDataProvider, que se define en xaml (también debería ser posible en el código):
<Window.Resources>
<XmlDataProvider
x:Name="myDP"
x:Key="MyData"
Source=""
XPath="/RootElement/Element"
IsAsynchronous="False"
IsInitialLoadEnabled="True"
debug:PresentationTraceSources.TraceLevel="High" /> </Window.Resources>
El proveedor de datos carga automáticamente el documento una vez que se establece la fuente. Aquí está el código:
m_DataProvider = this.FindResource("MyData") as XmlDataProvider;
FileInfo file = new FileInfo("MyXmlFile.xml");
m_DataProvider.Document = new XmlDocument();
m_DataProvider.Source = new Uri(file.FullName);
Tuve el mismo problema porque el archivo XML que estaba cargando estaba codificado con UTF-8-BOM (marca de orden de bytes UTF-8).
Cambió la codificación a UTF-8 en Notepad ++ y fue capaz de cargar el archivo XML en código.