2017-07-24 72 views
-1

假設我有這樣的XML文檔:如何使用XDocument對已授權的回車進行回車?

<x xml:space='preserve'>&#xd; 
</x> 

與此序列的字節爲<x/>的內容:

38 35 120 100 59 13 10 

我從W3C規範的理解是,該序列13 10will be replaced before parsing。爲了讓序列13 10顯示在我的分析樹中,我必須包含字符實體&xd;作爲clarified in a note in the W3C spec(我認識到這些來自XML-1.1而不是XML-1.0,但它們澄清了XML-1.0中令人困惑的事物,而未描述不同的行爲)。

2.11 End-of-Line Handling中所述,字面上存在於XML文檔中的所有#xD字符在執行任何其他處理之前被刪除或被#xA字符替換。獲得#xD字符以匹配此生產的唯一方法是在實體值文字中使用字符引用。

XDocument.Parse,這一切似乎工作正常。上述XML的文本內容爲13 10(而不是13 13 10),表明在解析之前保留了字符實體並將文字13 10替換爲10

但是,我不知道如何獲得XDocument.ToString()序列化時賦予換行符。即,我期望(XDocument xd) => XDocument.Parse($"{xd}")是一個無損功能。但是,如果我通過13 10作爲文本內容傳入XDocument實例,則該函數會將XDocument實例與10一起作爲文本內容輸出。看到這個演示:

var x = XDocument.Parse("<x xml:space='preserve'>&#xd;\r\n</x>"); 
present("content", x.Root.Value); // 13 10, expected 
present("formatted", $"{x}"); // inside <x/>: 13 10, unexpected 
x = XDocument.Parse($"{x}"); 
present("round tripped", x.Root.Value); // 10, unexpected 

// Note that when formatting the version with just 10 in the value, 
// we get Environment.NewLine in the formatted XML. So there is no 
// way to differentiate between 10 and 13 10 with XDocument because 
// it normalizes when serializing. 
present("roud tripped formatted", $"{x}"); // inside <x/>: 13 10, expected 

void present(string label, string thing) 
{ 
    Console.WriteLine(label); 
    Console.WriteLine(thing); 
    Console.WriteLine(string.Join(" ", Encoding.UTF8.GetBytes(thing))); 
    Console.WriteLine(); 
} 

你可以看到,當XDocument序列化時,它未能entitize回車作爲要麼&#xd;&#10;。結果是它失去了信息。我怎樣才能安全地編碼XDocument,以便我不會丟失任何東西,特殊的回車符,它們在我裝入的原始文檔中?

回答

0

要往返XDocument因爲這是有損不使用recommended/easy serialization methodsXDocument.ToString()。還要注意,即使你做了類似xd.ToString(SaveOptions.DisableFormatting)的東西,,解析樹中的任何回車將丟失

而是使用正確配置的XmlWriterXDocument.WriteTo。如果使用XmlWriter,則XmlWriter將能夠看到文檔包含文字回車並正確編碼它們。要指示它這樣做,請將XmlWritterSettings.NewLineHandling設置爲NewLineHandling.Entitize。您可能需要編寫一個擴展方法以使其更易於重用。

改變使用這種方法的演示低於:

var x = XDocument.Parse("<x xml:space='preserve'>&#xd;\r\n</x>"); 
present("content", x.Root.Value); // 13 10, expected 
present("formatted", toString(x)); // inside <x/>: 38 35 120 68 59 10 ("&#xD;\n"), acceptable 
x = XDocument.Parse(toString(x)); 
present("round tripped", x.Root.Value); // 13 10, expected 

string toString(XDocument xd) 
{ 
    using (var sw = new StringWriter()) 
    { 
     using (var writer = XmlWriter.Create(
      sw, 
      new XmlWriterSettings 
      { 
       NewLineHandling = NewLineHandling.Entitize, 
      })) 
     { 
      xd.WriteTo(writer); 
     } 
     return sw.ToString(); 
    } 
} 

void present(string label, string thing) 
{ 
    Console.WriteLine(label); 
    Console.WriteLine(thing); 
    Console.WriteLine(string.Join(" ", Encoding.UTF8.GetBytes(thing))); 
    Console.WriteLine(); 
}