實體在技術上被稱爲XML中的「數字字符引用」,當原始文檔被加載到XDocument
中時,它們被解析。這會讓您的問題難以解決,因爲在加載XDocument
之後,無法區分已解析的空白實體與無關緊要的空白(通常用於格式化純文本查看器的XML文檔)。因此,下面僅適用於您的文檔沒有任何不重要的空白。
System.Xml
庫允許通過將XmlWriterSettings
類的NewLineHandling
屬性設置爲Entitize
來保留空白實體。但是,在文本節點內,這隻會使\r
到
,而不是\n
到

。
最簡單的解決方案是從XmlWriter
類派生並覆蓋它的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));
}
在加載舊文檔或保存新文檔時會被替換嗎? – 2012-01-10 23:10:04
@Arnold:當我保存新的。 – mahdaeng 2012-01-12 16:51:22
理想的解決方案是修復XML的使用者,以便正確處理XML。 – svick 2012-01-18 18:25:53