The 

实体在 XML 中技术上称为“数字字符引用”,它们在原始文档加载到XDocument
。这使得您的问题很难解决,因为在XDocument
已加载。因此,以下内容仅适用于您的文档没有任何无关紧要的空格的情况。
The System.Xml
库允许通过设置来保留空白实体NewLineHandling http://msdn.microsoft.com/en-us/library/system.xml.xmlwritersettings.newlinehandling.aspx的财产XmlWriterSettings
上课到Entitize
。然而,在文本节点内,这只会实体化\r
to 
, 并不是\n
to 

.
最简单的解决方案是从XmlWriter
类并覆盖它的WriteString http://msdn.microsoft.com/en-us/library/system.xml.xmlwriter.writestring.aspx方法手动将空白字符替换为其数字字符实体。这WriteString
方法也恰好是 .NET 实体化不允许出现在文本节点中的字符的地方,例如语法标记&
, <
, and >
,分别实体化为&
, <
, and >
.
Since 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
call.
警告:以下简单的实现将不起作用,因为基础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
method:
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));
}