À l'aide de StringWriter pour la Sérialisation XML
Je suis actuellement à la recherche d'un moyen facile pour sérialiser des objets (en C# 3).
J'ai googlé quelques exemples et est venu avec quelque chose comme:
MemoryStream memoryStream = new MemoryStream ( );
XmlSerializer xs = new XmlSerializer ( typeof ( MyObject) );
XmlTextWriter xmlTextWriter = new XmlTextWriter ( memoryStream, Encoding.UTF8 );
xs.Serialize ( xmlTextWriter, myObject);
string result = Encoding.UTF8.GetString(memoryStream .ToArray());
Après la lecture de ce question je me suis demandé, pourquoi ne pas utiliser StringWriter? Il semble beaucoup plus facile.
XmlSerializer ser = new XmlSerializer(typeof(MyObject));
StringWriter writer = new StringWriter();
ser.Serialize(writer, myObject);
serializedValue = writer.ToString();
Un autre Problème, c'est que le premier exemple XML générés je ne pouvais pas l'écrire dans une colonne XML de SQL Server 2005 DB.
La première question est: Est-il une raison pourquoi je ne devrais pas utiliser StringWriter pour sérialiser un Objet quand j'en ai besoin comme une chaîne de caractères par la suite? Je n'ai jamais trouvé un résultat à l'aide de StringWriter quand googling.
La seconde est, bien entendu: Si vous ne devriez pas le faire avec StringWriter (pour quelques raisons que ce soit), ce qui serait une bonne et correcte?
Plus:
Comme il a déjà été mentionné par les deux réponses, je vais aller plus loin dans le XML DB problème.
Lors de l'écriture dans la Base de données, j'ai obtenu l'exception suivante:
Système.Les données.SqlClient.SqlException:
Analyse XML: ligne 1, du caractère, 38,
incapables de changer l'encodage
Pour la chaîne
<?xml version="1.0" encoding="utf-8"?><test/>
J'ai pris la chaîne créée à partir de la XmlTextWriter et vient de mettre en xml il. Celui-ci ne fonctionne pas (ni avec le manuel de l'insertion dans la DB).
Par la suite j'ai essayé d'insertion manuelle (juste écrit INSERT INTO ... ) avec encoding="utf-16" qui a également échoué.
Retrait de l'encodage totalement fonctionné ensuite. Après ce résultat, je suis passé de retour à la StringWriter code et voila, il a travaillé.
Problème: je ne comprends vraiment pas pourquoi.
à Christian Hayter: Avec ces tests, je ne suis pas sûr que je dois utiliser de l'utf-16 pour écrire à la DB. Ne serait pas le réglage du codage UTF-16 (dans la balise xml) fonctionne alors?
- Je vais sur l'expérience personnelle. SQL Server n'accepte que UTF-16, et si vous le passez à autre chose, vous êtes à la merci de SQL Server analyseur XML et ses tentatives pour convertir les données. Plutôt que d'essayer de trouver un moyen de tromper, je viens de passer en UTF-16 directement, ce qui sera toujours.
- Comment écrivez-vous cela à la base de données? Êtes-vous en passant une chaîne de caractères ou un tableau d'octets, ou de l'écriture d'un ruisseau? Si c'est de ces deux dernières formes, vous devez vous assurer que votre déclarée encodage correspond à l'encodage de vos données binaires.
- ouf. Le manuel de l'essayer j'ai fait une Requête dans le MS SQL Management Studio. Le "code" essais ont été écrits à une chaîne qui a été ensuite transmise à un O/R Mappeur qui écrit comme une chaîne de caractères (aussi loin que je pouvais suivre). En fait, je suis de passage de la chaîne qui a été créé dans les deux exemples donnés dans ma question.
- Pour info aux lecteurs - près de doublons: stackoverflow.com/questions/384974/... et stackoverflow.com/questions/3760788/...
- Je suis en train de changer ma accepté de répondre comme je le crois, il répond vraiment à ma question. Même si les autres réponses ont été de m'aider à continuer mon travail, dans le but de Stackoverflow, je pense, Salomon réponse sera aider les autres à mieux comprendre ce qui s'est passé. [Avertissement]: je n'ai pas trouvé le temps de vraiment vérifier la réponse.
Vous devez vous connecter pour publier un commentaire.
<TL;DR> Le problème est assez simple, en fait: vous ne correspondant pas à la déclaration de l'encodage (dans la déclaration XML) avec le type de données du paramètre d'entrée. Si vous avez ajouté manuellement
<?xml version="1.0" encoding="utf-8"?><test/>
à la chaîne, puis de déclarer laSqlParameter
pour être de typeSqlDbType.Xml
ouSqlDbType.NVarChar
vous donnera les "incapables de changer l'encodage d'erreur". Ensuite, lorsque vous insérez manuellement par l'intermédiaire de T-SQL, depuis que vous avez changé l'encodage déclaré êtreutf-16
, vous étiez clairement l'insertion d'uneVARCHAR
chaîne (pas de préfixe avec une majuscule, "N", donc un 8-bits, tel que UTF-8) et non pas uneNVARCHAR
chaîne (commençant par une majuscule, "N", d'où la 16-bits de l'UTF-16 LE codage).Le correctif doit avoir été aussi simple que:
encoding="utf-8"
: il suffit de ne pas ajouter de la déclaration XML.encoding="utf-16"
: soitSqlDbType.NVarChar
au lieu deSqlDbType.VarChar
🙂 (ou peut-être même passer à l'utilisation deSqlDbType.Xml
)(Réponse détaillée ci-dessous)
Toutes les réponses ici sont trop compliquées et inutiles (quel que soit le 121 et 184 jusqu'-voix de Christian et de Jon réponses, respectivement). Ils pourraient fournir des code de travail, mais aucun de ceux qui ont répondu à la question. Le problème est que personne n'a vraiment compris la question, qui est en fin de compte sur la façon dont le type de données XML dans SQL Server fonctionne. Rien contre ces deux clairement des gens intelligents, mais cette question a peu ou rien à voir avec la sérialisation XML. Enregistrement des données XML dans SQL Server est beaucoup plus facile que ce qui est sous-entendu ici.
Il n'importe pas vraiment comment le XML est produite aussi longtemps que vous suivez les règles pour créer des données XML dans SQL Server. J'ai une explication plus complète (y compris le travail un exemple de code pour illustrer les points décrits ci-dessous) dans une réponse sur cette question: Comment faire pour résoudre les “incapables de changer l'encodage” erreur lors de l'insertion de données XML dans SQL Server, mais les bases sont:
NVARCHAR(MAX)
ouXML
/SqlDbType.NVarChar
(maxsize = -1) ouSqlDbType.Xml
, ou si vous utilisez une chaîne de caractères littérale, alors il doit commencer par une majuscule "N".VARCHAR(MAX)
/SqlDbType.VarChar
(maxsize = -1), ou si vous utilisez une chaîne de caractères littérale, ensuite, il faut pas être préfixé avec un cas supérieur "N".Avec les points énoncés ci-dessus à l'esprit, et donné que les chaînes de caractères dans .NET sont toujours UTF-16 LE /UCS-2 LE (il n'y a pas de différence entre les deux termes de l'encodage), nous pouvons répondre à vos questions:
Non, votre
StringWriter
code semble pas y avoir de problème (du moins je ne vois pas de problèmes à mon de test limitée à l'aide de la 2e bloc de code à partir de la question).Il n'est pas nécessaire de fournir la déclaration XML. Quand il est absent, le codage doit être encodé en UTF-16 LE si vous passez la chaîne dans SQL Server comme
NVARCHAR
(c'est à direSqlDbType.NVarChar
) ouXML
(c'est à direSqlDbType.Xml
). L'encodage est supposé être à l'8 bits par défaut de la Page de Code si le passage enVARCHAR
(c'est à direSqlDbType.VarChar
). Si vous avez des non-standard des caractères ASCII (c'est à dire les valeurs 128 et ci-dessus) et passant commeVARCHAR
, alors vous aurez probablement voir le "?" pour BMP personnages et les "??" pour les Caractères Supplémentaires comme SQL Server vous permet de convertir le format UTF-16 de la chaîne d' .NET dans un 8-bit de la chaîne de la Base de données actuelle de la Page de Code avant de le reconvertir en UTF-16 /UCS-2. Mais vous ne devriez pas faire des erreurs.Sur l'autre main, si vous ne spécifiez la déclaration XML, puis vous doit passer dans SQL Server à l'aide de la correspondance de 8-bits ou 16-bits type de données. Donc, si vous avez une déclaration indiquant que le codage soit UCS-2 et UTF-16, alors vous doit passer comme
SqlDbType.NVarChar
ouSqlDbType.Xml
. Ou, si vous avez une déclaration indiquant que le codage est l'un des 8-bits options (c'est à direUTF-8
,Windows-1252
,iso-8859-1
, etc), alors vous doit passer commeSqlDbType.VarChar
. L'échec pour correspondre à la déclaration de l'encodage avec le bon 8 ou 16 bits de SQL Server données en résultera le "incapables de changer l'encodage d'erreur que vous obtenez.Par exemple, à l'aide de votre
StringWriter
à base de code de sérialisation, j'ai tout simplement imprimé la chaîne résultante de l'XML et l'a utilisé dans SSMS. Comme vous pouvez le voir ci-dessous, la déclaration XML est inclus (parce queStringWriter
n'a pas une option pourOmitXmlDeclaration
commeXmlWriter
n'), ce qui ne pose pas de problème tant que vous passez la chaîne dans le Serveur SQL correcte type de données:Comme vous pouvez le voir, il prend même en charge les caractères au-delà de la norme ASCII, étant donné que
ሴ
est BMP Point de Code U+1234, etest Complémentaire de Caractère de Point de Code U+1F638. Toutefois, les éléments suivants:
résultats dans l'erreur suivante:
Ergo, tout cela explication de côté, la solution complète à votre question de départ est:
Vous ont été clairement passage de la chaîne en tant que
SqlDbType.VarChar
. Interrupteur àSqlDbType.NVarChar
et il fonctionne sans avoir besoin de passer par l'étape supplémentaire de retrait de la déclaration XML. C'est préférable sur le maintienSqlDbType.VarChar
et la suppression de la déclaration XML parce que cette solution permettra d'éviter la perte de données lorsque le fichier XML inclut non-standard des caractères ASCII. Par exemple:Comme vous pouvez le voir, il n'y a pas d'erreur cette fois, mais maintenant, il est de la perte de données .
SqlDbType.NVarChar
ouXml
.Un problème avec
StringWriter
est que par défaut il ne vous laisse pas définir l'encodage qui il fait de la publicité - de sorte que vous pouvez vous retrouver avec un document XML de la publicité de son encodage en UTF-16, ce qui signifie que vous devez coder en UTF-16 si vous écrivez dans un fichier. J'ai une petite classe pour vous aider à bien:Ou si vous avez seulement besoin de l'UTF-8 (ce qui est tout j'ai souvent besoin d'):
Comme pour expliquer pourquoi vous ne pouvez pas enregistrer votre XML de la base de données, vous devrez nous donner plus de détails sur ce qui s'est passé lorsque vous avez essayé, si vous voulez être en mesure de diagnostiquer et de réparer.
StringWriter
ne prend pas en compte l'encodage, mais jamais le moins, merci pour ce chouette petit méthode 🙂MemoryStream
et unStreamWriter
avec le bon encodage.StreamWriter
est unTextWriter
(le type quiXmlWriter.Create
attend) avec personnalisable encodage, après tout.myEncoding.GetString(memstream.GetBuffer());
. Et, si elle n'a finalement besoin d'être écrites dans un fichier,File.WriteAllText(filePath, xmlmessagestr, myEncoding);
.ToString()
🙂 C'est une belle solution de contournement si vous avez besoin de seulement une ou deux fois, mais pour la réutilisabilité, je préfère avoir les classes indiquées ici.Encoding
propriété deTextWriter
. Étant donné queStringWriter
n'impliquent pas des octets n'importe où, je pense qu'il serait plus clair de le considérer comme n'appliquant pas aucun encodage plutôt qu'une chaîne "en" UTF-16. Cette solution "fonctionne correctement" aux fins de permettre à unStringWriter
pour faire la publicité d'un codage particulier pour un autre code qui l'utilise. Oui, si vous convertissez la chaîne binaire, plus tard, vous devez vous assurer que vous utilisez le bon encodage, mais c'est bien dans de nombreux cas.TextWriter.Encoding
spécifiquement souligne: "Cette propriété est nécessaire pour certaines XML scénarios où un en-tête doit être écrit contenant l'encodage utilisé par le TextWriter. Cela permet au code XML de consommer de l'arbitraire TextWriter et de générer le bon en-tête XML." Le but de ce code est de générer un en-tête XML avec l'encodage spécifié - oui, de quelle façon avez-vous justifier en prétendant que "cela ne peut pas fonctionner correctement"?Quand serialising un document XML à un .NET de chaîne, le codage doit être configuré en UTF-16. Les chaînes de caractères sont stockées en tant que UTF-16 en interne, c'est donc le seul encodage qui fait sens. Si vous souhaitez stocker les données dans un autre encodage, vous utilisez un tableau d'octets au lieu.
SQL Server fonctionne sur un principe similaire; toute chaîne de caractères passée en un
xml
colonne doit être codé en UTF-16. SQL Serveur rejette toute chaîne où la déclaration XML n'a pas de spécifier l'encodage UTF-16. Si la déclaration XML n'est pas présent, alors le XML standard exige que la valeur par défaut est UTF-8, SQL Server va rejeter ainsi.Gardant cela à l'esprit, voici quelques méthodes utiles pour faire la conversion.
StringWriter
attend. Voir ma réponse. Le format de stockage interne n'est pas pertinent ici.Nothing
est implicitement convertible en tout type. J'ai corrigé leDeserialize
code. LeSerialize
avertissement doit être un Resharper seule chose, le compilateur sur sa propre n'a pas d'objet et il est légal de le faire.NVARCHAR
de données doit être en UTF-16 LE.VARCHAR
de données (variable/paramètre déclaré en tant que tel, ou une chaîne littérale pas avec le préfixe "N") peut être n'importe quel 8-bits de codage. "SQL Serveur rejette toute chaîne où la déclaration XML n'a pas de spécifier l'encodage UTF-16". Pas de. Cela se produit uniquement lors du passage dansNVARCHAR
de données.VARCHAR
de données peut (et doit) spécifier valide 8-bits, ce qui peut êtreUTF-8
, ouWindows-1252
, etc. Suite (désolé)...VARCHAR
chaîne, l'encodage est supposé être à la Page de Code de Classement par défaut de l'actuel DB (ce qui ne pouvait pas être en UTF-8 jusqu'à ce que SQL Server 2019), sinon, il sera pris que ce qui est spécifié dans la déclaration XML, qui peut être en UTF-8 ou beaucoup d'autres. Sinon, si c'est unNVARCHAR
chaîne, le codage doit être encodé en UTF-16 (UTF-16 LE plus précisément). Merci de corriger ou de supprimer cette réponse. Merci.Tout d'abord, méfiez-vous de trouver des exemples anciens. Vous avez trouvé un qui utilise
XmlTextWriter
, qui est déprécié que de .NET 2.0.XmlWriter.Create
devrait être utilisé à la place.Voici un exemple de sérialisation d'un objet dans une colonne XML:
XmlReader
peut l'analyser. Il sera envoyé pré-analysée à la base de données, puis de la DB n'a pas besoin de savoir quelque chose au sujet de l'encodage des caractères UTF-16 ou autrement. En particulier, notez que les déclarations XML ne sont même pas persisté avec les données dans la base de données, indépendamment de la méthode utilisée pour l'insérer. Merci de ne pas faire de gaspillage en cours d'exécution XML par des conversions, comme dans d'autres réponses ici et d'ailleurs.Il a été recouverte par ailleurs, mais il suffit de changer la ligne de codage de la source XML à "utf-16" permet le XML pour être inséré dans un Serveur SQL xml'data type.
Le résultat est tout de XML texte est inséré dans le xml de type de données de champ, mais le 'header' de la ligne est supprimée. Ce que vous voyez dans le résultat de l'enregistrement est juste
À l'aide de la méthode de sérialisation décrit dans la section "Répondu" entrée est une façon d'inclure le fichier d'entête dans le champ cible, mais le résultat est que le reste du texte XML est enfermé dans un XML
<string></string>
tag.La table de l'adaptateur dans le code est une classe construite automatiquement à l'aide de Visual Studio 2013 "Ajouter une Nouvelle Source de Données: l'assistant. Les cinq paramètres de la méthode d'Insertion de la carte de champs dans une table SQL Server.