Pourquoi C # XmlDocument.LoadXml (chaîne) échoue-t-il lorsqu’un en-tête XML est inclus?

Quelqu’un at-il une idée de la raison pour laquelle l’exemple de code suivant échoue avec une exception XmlException “Les données au niveau racine ne sont pas valides. Ligne 1, position 1.”

var body = " ......" XmlDocument bodyDoc = new XmlDocument(); bodyDoc.LoadXml(body); 

Contexte

Bien que l’encodage de votre question soit UTF-16, vous n’avez pas correctement échappé la chaîne. Je n’étais donc pas sûr de bien transposer la chaîne dans votre question.

J’ai rencontré la même exception:

System.Xml.XmlException: les données au niveau racine ne sont pas valides. Ligne 1, position 1.

Cependant, mon code ressemblait à ceci:

 ssortingng xml = "\nThis is a Test"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xml); 

Le problème

Le problème est que les chaînes sont stockées en interne sous la forme UTF-16 dans .NET, mais le codage spécifié dans l’en-tête du document XML peut être différent. Par exemple:

  

De la documentation MSDN pour Ssortingng ici :

Chaque caractère Unicode d’une chaîne est défini par une valeur scalaire Unicode, également appelée sharepoint code Unicode ou valeur ordinale (numérique) du caractère Unicode. Chaque sharepoint code est codé à l’aide du codage UTF-16 et la valeur numérique de chaque élément du codage est représentée par un object Char.

Cela signifie que lorsque vous transmettez XmlDocument.LoadXml () votre chaîne avec un en-tête XML, il doit dire que l’encodage est UTF-16. Sinon, le codage sous-jacent ne correspondra pas au codage indiqué dans l’en-tête et entraînera une exception XmlException.

La solution

La solution à ce problème consiste à vérifier que le codage utilisé dans la méthode Load ou LoadXml correspond à ce que vous dites dans l’en-tête XML. Dans mon exemple ci-dessus, modifiez votre en-tête XML pour indiquer UTF-16 ou pour encoder l’entrée dans UTF-8 et utilisez l’une des méthodes XmlDocument.Load .

Vous trouverez ci-dessous un exemple de code montrant comment utiliser un MemoryStream pour générer un XmlDocument à l’aide d’une chaîne qui définit un document XML d’encodage UTF-8 (mais bien sûr, une chaîne UTF-16 .NET).

 ssortingng xml = "\nThis is a Test"; // Encode the XML ssortingng in a UTF-8 byte array byte[] encodedSsortingng = Encoding.UTF8.GetBytes(xml); // Put the byte array into a stream and rewind it to the beginning MemoryStream ms = new MemoryStream(encodedSsortingng); ms.Flush(); ms.Position = 0; // Build the XmlDocument from the MemorySteam of UTF-8 encoded bytes XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(ms); 

Solution simple et efficace: au lieu d’utiliser la méthode LoadXml() , utilisez la méthode Load()

Par exemple:

 XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load("sample.xml"); 

Essaye ça:

 XmlDocument bodyDoc = new XmlDocument(); bodyDoc.XMLResolver = null; bodyDoc.Load(body); 

Je l’ai compris. Lisez la documentation MSDN et il est dit d’utiliser .Load au lieu de LoadXml lors de la lecture des chaînes. Découvert que cela fonctionne 100% du temps. Curieusement, l’utilisation de SsortingngReader pose des problèmes. Je pense que la raison principale est que ceci est une chaîne codée Unicode et que cela pourrait causer des problèmes parce que SsortingngReader est uniquement 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); 

Cela a fonctionné pour moi:

 var xdoc = new XmlDocument { XmlResolver = null }; xdoc.LoadXml(xmlFragment); 

Cela a vraiment sauvé ma journée.

J’ai écrit une méthode d’extension basée sur la réponse de Zach, et je l’ai étendue pour utiliser l’encodage en tant que paramètre, permettant d’utiliser différents encodages à côté de UTF-8, et j’ai enveloppé le MemoryStream dans une instruction ‘using’.

 public static class XmlHelperExtentions { ///  /// Loads a ssortingng through .Load() instead of .LoadXml() /// This prevents character encoding problems. ///  ///  ///  public static void LoadSsortingng(this XmlDocument xmlDocument, ssortingng xmlSsortingng, Encoding encoding = null) { if (encoding == null) { encoding = Encoding.UTF8; } // Encode the XML ssortingng in a byte array byte[] encodedSsortingng = encoding.GetBytes(xmlSsortingng); // Put the byte array into a stream and rewind it to the beginning using (var ms = new MemoryStream(encodedSsortingng)) { ms.Flush(); ms.Position = 0; // Build the XmlDocument from the MemorySteam of UTF-8 encoded bytes xmlDocument.Load(ms); } } } 

J’ai eu le même problème lors du passage du chemin absolu au chemin relatif pour mon fichier xml. Ce qui suit résout à la fois le chargement et l’utilisation de problèmes relatifs au chemin source. En utilisant un XmlDataProvider, qui est défini dans xaml (devrait être possible dans le code aussi):

     

Le fournisseur de données charge automatiquement le document une fois la source définie. Voici le code:

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

Ligne simple:

bodyDoc.LoadXml(new MemoryStream(Encoding.Unicode.GetBytes(body)));

J’ai eu le même problème parce que le fichier XML que je téléchargeais était encodé en utilisant UTF-8-BOM (UTF-8 byte-order mark).

Passé le codage à UTF-8 dans Notepad ++ et a pu charger le fichier XML dans le code.