Субъекты 

технически называются «ссылками на числовые символы» в XML и разрешаются при загрузке исходного документа в XDocument
.Это делает вашу проблему проблематичной для решения, так как нет способа отличить разрешенные пробельные объекты от незначительного пробела (обычно используемого для форматирования документов XML для средств просмотра обычного текста) после загрузки XDocument
.Таким образом, нижеприведенное применимо только в том случае, если в вашем документе нет незначительных пробелов.
Библиотека System.Xml
позволяет сохранять пробельные объекты, устанавливая свойство NewLineHandling
для XmlWriterSettings
класс до Entitize
.Однако в текстовых узлах это будет давать только права \r
на 
, а не \n
на 

.
Самое простое решение - наследовать класс XmlWriter
и переопределять его WriteString
метод для ручной замены символов пробела их числовыми символами.Метод WriteString
также является тем местом, где .NET разрешает символы, которые не разрешены появляться в текстовых узлах, такие как синтаксические маркеры &
, <
и >
, которые соответственно имеют право на &
, <
и >
.
Поскольку XmlWriter
является абстрактным, мы будем наследовать от XmlTextWriter
, чтобы избежать необходимости реализовывать все абстрактные методы предыдущего класса.Вот краткая и быстрая реализация:
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;
}
}
}
}
Если она предназначена для использования в производственной среде, вам следует покончить с частью c.ToString()
, поскольку она очень неэффективна.Вы можете оптимизировать код, упаковав подстроки исходной text
, которые не содержат символов, которые вы хотите назначить, и объединяя их в один вызов base.WriteString
.
Слово предупреждения:Следующая наивная реализация не будет работать, так как базовый метод WriteString
заменит любые &
символы на &
, в результате чего \r
будет расширен до &#xA;
.
public override void WriteString(string text)
{
text = text.Replace("\r", "
");
text = text.Replace("\n", "
");
text = text.Replace("\t", "	");
base.WriteString(text);
}
Наконец, чтобы сохранить XDocument
в файле или потоке назначения, просто используйте следующий фрагмент:
using (var textWriter = new StreamWriter(destination))
using (var xmlWriter = new EntitizingXmlWriter(textWriter))
document.Save(xmlWriter);
Надеюсь, это поможет!
Редактировать : Для справки,Вот оптимизированная версия переопределенного метода WriteString
:
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));
}