2011-11-24 35 views
13

.NET's XmlTextWriter tạo tệp xml không hợp lệ.XmlTextWriter viết ký tự không chính xác

Trong XML, một số ký tự điều khiển được cho phép, như 'tab ngang' (	), nhưng một số khác thì không, như 'tab dọc' (). (Xem spec.)

Tôi có một chuỗi chứa ký tự điều khiển UTF-8 không được phép trong XML.
Mặc dù XmlTextWriter thoát khỏi ký tự, kết quả XML là ofcourse vẫn không hợp lệ.

Làm cách nào để đảm bảo rằng XmlTextWriter không bao giờ tạo ra tệp XML bất hợp pháp?

Hoặc, nếu không thể thực hiện việc này với XmlTextWriter, làm cách nào để loại bỏ các ký tự điều khiển cụ thể không được phép trong XML từ chuỗi?

Ví dụ mã:

using (XmlTextWriter writer = 
    new XmlTextWriter("test.xml", Encoding.UTF8)) 
{ 
    writer.WriteStartDocument(); 
    writer.WriteStartElement("Test"); 
    writer.WriteValue("hello \xb world"); 
    writer.WriteEndElement(); 
    writer.WriteEndDocument(); 
} 

Output:

<?xml version="1.0" encoding="utf-8"?><Test>hello &#xB; world</Test> 
+0

Bạn không thể có tab dọc được thoát trong XML? Bạn có thể tham khảo các tiêu chuẩn? – Jodrell

+0

@Jodrell Đúng vậy, bạn không thể. XML dành cho văn bản, không dành cho ký tự điều khiển hoặc dữ liệu nhị phân. http://www.w3.org/TR/REC-xml/#charsets – jasso

Trả lời

10

Tài liệu này của một hành vi được giấu trong documentation of the WriteString method nhưng có vẻ như nó áp dụng cho cả lớp.

Hành vi mặc định của một XmlWriter tạo bằng Tạo là để ném một ArgumentException khi cố gắng viết các giá trị nhân vật trong phạm vi 0x-0x1F (trừ trắng nhân vật không gian 0x9, 0xA, và 0xD). Các ký tự XML không hợp lệ này có thể được viết bằng cách tạo XmlWriter với thuộc tính CheckCharacters được đặt thành false. Làm như vậy sẽ dẫn đến kết quả là trong các ký tự được thay thế bằng các ký tự số (&#0; đến &#0x1F). Ngoài ra, một XmlTextWriter được tạo với toán tử mới sẽ thay thế các ký tự không hợp lệ bằng ký tự số các thực thể theo mặc định.

Vì vậy, có vẻ như bạn kết thúc viết các ký tự không hợp lệ vì bạn đang sử dụng lớp XmlTextWriter. Một giải pháp tốt hơn cho bạn sẽ là sử dụng XmlWriter Class thay thế.

+0

Hơi lạ, nhưng rõ ràng mặc dù hàm tạo 'XmlTextWriter' tồn tại, bạn không được phép sử dụng nó: http: // msdn. microsoft.com/en-us/library/kkz7cs0d.aspx –

1

Các bộ lưu trữ .NET tích hợp chẳng hạn như SecurityElement.Escape cũng không thoát đúng cách.

  • Bạn có thể thiết lập CheckCharacters-false trên cả hai tác giả và người đọc nếu ứng dụng của bạn là người duy nhất tương tác với tập tin. Tệp XML kết quả sẽ vẫn là kỹ thuật không hợp lệ.

Xem:

XmlWriterSettings xmlWriterSettings = new XmlWriterSettings(); 
xmlWriterSettings.Encoding = new UTF8Encoding(false); 
xmlWriterSettings.CheckCharacters = false; 
var sb = new StringBuilder(); 
var w = XmlWriter.Create(sb, xmlWriterSettings); 
w.WriteStartDocument(); 
w.WriteStartElement("Test"); 
w.WriteString("hello \xb world"); 
w.WriteEndElement(); 
w.WriteEndDocument(); 
w.Close(); 
var xml = sb.ToString(); 
  • Nếu thiết CheckCharacters để true (mà nó là theo mặc định) là một chút quá khắt khe vì nó sẽ chỉ đơn giản là ném một ngoại lệ một cách tiếp cận khác đó là khoan dung hơn đối với XML không hợp lệ các ký tự sẽ chỉ để tách chúng:

Googling một chút mang lại danh sách trắng XmlTextEncoder tuy nhiên, nó cũng sẽ xóa DEL và những người khác trong phạm vi U + 007F – U + 0084, U + 0086 – U + 009F theo Valid XML Characters trên wikipedia chỉ hợp lệ trong các ngữ cảnh nhất định và RFC đề cập đến các ký tự không được khuyến khích nhưng vẫn hợp lệ.

public static class XmlTextExtentions 
{ 
    private static readonly Dictionary<char, string> textEntities = new Dictionary<char, string> { 
     { '&', "&amp;"}, { '<', "&lt;" }, { '>', "&gt;" }, 
     { '"', "&quot;" }, { '\'', "&apos;" } 
    }; 
    public static string ToValidXmlString(this string str) 
    { 
     var stripped = str 
      .Select((c,i) => new 
      { 
       c1 = c, 
       c2 = i + 1 < str.Length ? str[i+1]: default(char), 
       v = XmlConvert.IsXmlChar(c), 
       p = i + 1 < str.Length ? XmlConvert.IsXmlSurrogatePair(str[i + 1], c) : false, 
       pp = i > 0 ? XmlConvert.IsXmlSurrogatePair(c, str[i - 1]) : false 
      }) 
      .Aggregate("", (s, c) => {     
       if (c.pp) 
        return s; 
       if (textEntities.ContainsKey(c.c1)) 
        s += textEntities[c.c1]; 
       else if (c.v) 
        s += c.c1.ToString(); 
       else if (c.p) 
        s += c.c1.ToString() + c.c2.ToString(); 
       return s; 
      }); 
     return stripped; 
    } 
} 

này vượt qua tất cả các bài kiểm tra XmlTextEncoder trừ một trong những hy vọng nó dải DELXmlConvert.IsXmlChar, Wikipedia, và các nhãn hiệu spec như một ký tự hợp lệ (mặc dù nản).

3

Chỉ cần thấy câu hỏi này khi tôi đã phải vật lộn với vấn đề tương tự và tôi đã kết thúc giải quyết nó với một regex:

return Regex.Replace(s, @"[\u0000-\u0008\u000B\u000C\u000E-\u001F]", ""); 

Hy vọng nó sẽ giúp ai đó như một giải pháp thay thế.

Các vấn đề liên quan