2012-10-17 17 views
7

Chúng tôi thu thập rất nhiều chuỗi và gửi chúng cho khách hàng của chúng tôi trong các đoạn xml. Những chuỗi này có thể chứa bất kỳ ký tự nào theo nghĩa đen. Chúng tôi đã nhìn thấy một lỗi gây ra bởi cố gắng để serialize trường hợp XElement có chứa ký tự "xấu". Dưới đây là ví dụ:Xử lý các chuỗi để chèn vào 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 

Đoạn mã trên tạo ra ngoại lệ tại dòng được chỉ định. Dưới đây là stacktrace:

 
'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) 

Nghi ngờ của tôi là đây không phải là hành vi đúng và thẻ xấu phải được thoát vào XML. Cho dù điều này là mong muốn hay không là một câu hỏi tôi sẽ trả lời sau.

Vì vậy, đây là câu hỏi:

Có một số cách xử lý chuỗi như rằng lỗi này có thể không xảy ra, hoặc nên tôi chỉ đơn giản tước tất cả các ký tự bên dưới char 0x20 và chéo ngón tay của tôi?

+0

Câu hỏi hay. Trên thực tế, bạn không nên bỏ * tất cả * ký tự bên dưới 0x20, vì một số trong số chúng được thoát đúng cách (ví dụ: CR, LF, TAB ...). Nhưng tôi không thể thấy lý do nào khiến những người khác không trốn thoát ... –

+0

Khách hàng của bạn có thực sự cần những ký tự đó trong chuỗi không? – climbage

+0

No. Chắc chắn là không. Chúng được trả về một hộp văn bản WPF hoặc như một mvcstring trong một webapp. Trong thực tế, trong trường hợp của chúng tôi, thậm chí combo/crf/tab của @ThomasLevesque có thể bị tước đi vì chúng tôi đang mong đợi một dòng. Những chuỗi này thực hiện một chuyến đi đến các máy chủ của chúng tôi thông qua các thẻ idv3, phần mềm phát sóng và các máy chủ shoutcast. Nó khá có thể là mã hóa đã bị xáo trộn trên đường đi. Tôi nghĩ rằng sửa chữa của tôi là hoàn toàn áp dụng đối với chúng tôi. Tôi vẫn còn bối rối bởi ngoại lệ này, và muốn xác nhận rằng tôi dường như đã phát hiện ra một lỗi trong .net. – spender

Trả lời

5

Đây là những gì tôi đang sử dụng trong mã của tôi:

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; 
    } 

Tất cả các nhân vật dưới đây 0x20 (trừ \ r \ n \ t) được thay thế bằng mã unicode XML của họ: 0x1f => "& # 001f" . Trình phân tích cú pháp Xml sẽ tự động không hiển thị trở lại 0x1f khi đọc tệp. Chỉ cần sử dụng thuộc tính XAttribute mới ("thuộc tính", Fix (yourString))

Nó hoạt động cho nội dung XElement có lẽ cũng nên hoạt động cho XAttributes.

+0

Sửa lỗi tương tự. Vì thiếu một câu trả lời hấp dẫn hơn, tôi sẽ cho bạn điểm. – spender

8

Một chút đào với ILSpy tiết lộ rằng người ta có thể sử dụng trường XmlWriter/ReaderSettings.CheckCharacters để kiểm soát có hay không một ngoại lệ được ném cho các ký tự không hợp lệ. Mượn từ phương pháp XNode.ToString và phương pháp XDocument.Parse, tôi đã đưa ra các ví dụ sau:

Để stringify một đối tượng XLinq với các nhân vật (điều khiển) không hợp lệ:

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(); 
} 

Để phân tích một Đối tượng XLinq có ký tự không hợp lệ:

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

Tuyệt vời, cảm ơn rất nhiều. –