Объекты 

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

.
Самое простое решение состоит в том, чтобы получить класс XmlWriter
и переопределить его метод WriteString
, чтобы вручную заменить символы пробелов на их числовые символьные сущности. Метод WriteString
также случается быть местом, где .NET entitizes символы, которые не разрешено появляться в текстовых узлах, таких как маркеры синтаксиса &
, <
и >
, которые соответственно к &
преобразуются в сущности, <
и >
.
С 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);
Надеется, что это помогает!
Edit: Для справки, здесь является оптимизированной версией переопределен 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));
}
Заменяются ли при загрузке старого документа или при его сохранении? –
@Arnold: Когда я сохраняю новый. – mahdaeng
Идеальное решение - исправить потребителя вашего XML, чтобы он правильно обрабатывал XML. – svick