2012-10-17 34 views
7

我們收集大量字符串並將它們以xml片段發送給我們的客戶端。這些字符串可以包含字面上的任何字符。我們發現嘗試序列化包含「壞」字符的XElement實例導致的錯誤。這裏有一個例子:處理字符串以插入XElement

var message = new XElement("song"); 
char c = (char)0x1a; //sub 
var someData = string.Format("some{0}stuff", c); 
var attr = new XAttribute("someAttr", someData); 
message.Add(attr); 
string msgStr = message.ToString(SaveOptions.DisableFormatting); //exception here 

上面的代碼在指定的行生成一個異常。這裏的堆棧跟蹤:

 
'SUB', hexadecimal value 0x1A, is an invalid character. System.ArgumentException System.ArgumentException: '', hexadecimal value 0x1A, is an invalid character. 
    at System.Xml.XmlEncodedRawTextWriter.InvalidXmlChar(Int32 ch, Char* pDst, Boolean entitize) 
    at System.Xml.XmlEncodedRawTextWriter.WriteAttributeTextBlock(Char* pSrc, Char* pSrcEnd) 
    at System.Xml.XmlEncodedRawTextWriter.WriteString(String text) 
    at System.Xml.XmlWellFormedWriter.WriteString(String text) 
    at System.Xml.XmlWriter.WriteAttributeString(String prefix, String localName, String ns, String value) 
    at System.Xml.Linq.ElementWriter.WriteStartElement(XElement e) 
    at System.Xml.Linq.ElementWriter.WriteElement(XElement e) 
    at System.Xml.Linq.XElement.WriteTo(XmlWriter writer) 
    at System.Xml.Linq.XNode.GetXmlString(SaveOptions o) 

我懷疑這是不正確的行爲,壞的字符應該轉義成XML。這是否可取是我稍後會回答的一個問題。

所以這裏的問題:

是否有處理字符串,例如,可能不會出現此錯誤的一些方法,或者我應該簡單地剝離低於焦炭0x20所有字符,穿過我的手指?

+0

好問題。實際上,你不應該去除0x20以下的所有*字符,因爲它們中的一些被正確地轉義了(例如CR,LF,TAB ...)。但我看不到任何其他人沒有逃脫的原因...... –

+0

您的客戶是否真的需要這些字符串中的字符? – climbage

+0

不,絕對不是。它們要麼呈現給WPF文本框,要麼呈現爲Web應用程序中的mvcstring。事實上,在我們的例子中,甚至@ThomasLevesque的cr/lf/tab組合可以被剝離,因爲我們期待着一條線。這些字符串通過idv3標籤,廣播軟件和shoutcast服務器進入我們的服務器。編碼在編碼過程中很可能已經被破壞。我認爲我的修補程序完全適用於我們。我仍然對這個例外感到困惑,並希望確認我似乎發現了.net中的一個錯誤。 – spender

回答

5

這是我在用我的代碼:

static Lazy<Regex> ControlChars = new Lazy<Regex>(() => new Regex("[\x00-\x1f]", RegexOptions.Compiled)); 

    private static string FixData_Replace(Match match) 
    { 
     if ((match.Value.Equals("\t")) || (match.Value.Equals("\n")) || (match.Value.Equals("\r"))) 
      return match.Value; 

     return "&#" + ((int)match.Value[0]).ToString("X4") + ";"; 
    } 

    public static string Fix(object data, MatchEvaluator replacer = null) 
    { 
     if (data == null) return null; 
     string fixed_data; 
     if (replacer != null) fixed_data = ControlChars.Value.Replace(data.ToString(), replacer); 
     else fixed_data = ControlChars.Value.Replace(data.ToString(), FixData_Replace); 
     return fixed_data; 
    } 

所有字符波紋管爲0x20(除\ r \ n \ t)將通過XML的unicode碼被替換:爲0x1F => 「&#001F」 。 當讀取文件時,Xml解析器應該自動將其還原爲0x1f。 只需使用新的XAttribute(「屬性」,Fix(yourString))

它適用於XElement內容,它可能也適用於XAttributes。

+0

用類似的東西修復。由於缺乏更有說服力的答案,我會給你提出觀點。 – spender

8

用ILSpy稍微挖掘一下,發現可以使用XmlWriter/ReaderSettings.CheckCharacters字段來控制是否拋出無效字符的異常。從XNode.ToString方法和XDocument.Parse方法借用,我已經想出以下的實施例:

要字符串化具有無效(對照)字符的XLINQ對象:

XDocument xdoc = XDocument.Parse("<root>foo</root>"); 
using (StringWriter stringWriter = new StringWriter()) 
{ 
    XmlWriterSettings xmlWriterSettings = new XmlWriterSettings { OmitXmlDeclaration = true, CheckCharacters = false }; 
    using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, xmlWriterSettings)) 
    { 
     xdoc.WriteTo(xmlWriter); 
    } 

    return stringWriter.ToString(); 
} 

來解析帶有無效字符的XLinq對象:

XDocument xdoc; 
using (StringReader stringReader = new StringReader(text)) 
{ 
    XmlReaderSettings xmlReaderSettings = new XmlReaderSettings { CheckCharacters = false, DtdProcessing = DtdProcessing.Parse, MaxCharactersFromEntities = 10000000L, XmlResolver = null }; 
    using (XmlReader xmlReader = XmlReader.Create(stringReader, xmlReaderSettings)) 
    { 
     xdoc = XDocument.Load(xmlReader); 
    } 
} 
+0

非常好,非常感謝。 –