Las entidades 

se denominan técnicamente "referencias de caracteres numéricos" en XML, y se resuelven cuando el documento original se carga en el XDocument
. Esto hace que su problema sea problemático de resolver, ya que no hay forma de distinguir entidades de espacio en blanco resueltas de espacios en blanco insignificantes (normalmente se utiliza para formatear documentos XML para lectores de texto sin formato) después de cargar el XDocument
. Por lo tanto, lo siguiente solo aplica si su documento no tiene espacios en blanco insignificantes.
La biblioteca System.Xml
le permite a uno para conservar espacio en blanco entidades estableciendo la propiedad NewLineHandling
de la clase XmlWriterSettings
a Entitize
. Sin embargo, dentro de los nodos de texto, esto solo daría derecho a \r
a 
, y no a \n
a 

.
La solución más fácil es derivar de la clase XmlWriter
y anular su método WriteString
para reemplazar manualmente los caracteres de espacios en blanco con sus entidades de caracteres numéricos. El método WriteString
también pasa a ser el lugar donde .NET entitizes caracteres que no están permitidos para aparecer en los nodos de texto, tales como los marcadores de sintaxis &
, <
, y >
, que están entitized respectivamente a &
, <
, y >
.
Dado que XmlWriter
es abstracto, derivaremos de XmlTextWriter
para evitar tener que implementar todos los métodos abstractos de la clase anterior. Aquí es una implementación rápida y sucia-:
public class EntitizingXmlWriter : XmlTextWriter
{
public EntitizingXmlWriter(TextWriter writer) :
base(writer)
{ }
public override void WriteString(string text)
{
foreach (char c in text)
{
switch (c)
{
case '\r':
case '\n':
case '\t':
base.WriteCharEntity(c);
break;
default:
base.WriteString(c.ToString());
break;
}
}
}
}
Si diseñado para su uso en un entorno de producción, que querría acabar con la parte c.ToString()
, ya que es muy ineficiente. Puede optimizar el código agrupando subcadenas del text
original que no contienen ninguno de los caracteres que desea titularizar y alimentarlas juntas en una sola llamada base.WriteString
.
Una palabra de advertencia: La siguiente aplicación ingenua no funcionará, ya que la base WriteString
método reemplazaría cualquier &
caracteres con &
, causando con ello \r
se expanda a &#xA;
.
public override void WriteString(string text)
{
text = text.Replace("\r", "
");
text = text.Replace("\n", "
");
text = text.Replace("\t", "	");
base.WriteString(text);
}
Finalmente, para salvar su XDocument
en un archivo de destino o un arroyo, sólo tiene que utilizar el siguiente fragmento:
using (var textWriter = new StreamWriter(destination))
using (var xmlWriter = new EntitizingXmlWriter(textWriter))
document.Save(xmlWriter);
Espero que esto ayude!
Editar: Para referencia, aquí es una versión optimizada de la WriteString
método anulado:
public override void WriteString(string text)
{
// The start index of the next substring containing only non-entitized characters.
int start = 0;
// The index of the current character being checked.
for (int curr = 0; curr < text.Length; ++curr)
{
// Check whether the current character should be entitized.
char chr = text[curr];
if (chr == '\r' || chr == '\n' || chr == '\t')
{
// Write the previous substring of non-entitized characters.
if (start < curr)
base.WriteString(text.Substring(start, curr - start));
// Write current character, entitized.
base.WriteCharEntity(chr);
// Next substring of non-entitized characters tentatively starts
// immediately beyond current character.
start = curr + 1;
}
}
// Write the trailing substring of non-entitized characters.
if (start < text.Length)
base.WriteString(text.Substring(start, text.Length - start));
}
¿Se reemplaza cuando carga el documento anterior o cuando guarda el nuevo? –
@Arnold: cuando guardo el nuevo. – mahdaeng
La solución ideal sería corregir al consumidor de su XML, para que maneje XML correctamente. – svick