2008-12-29 50 views
36

Danh sách các nhân vật XML hợp lệ cũng được biết, theo quy định của spec nó:Unicode Regex; Không hợp lệ ký tự XML

#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] 

Câu hỏi của tôi là có hay không nó có thể làm cho một biểu thức chính quy PCRE cho điều này (hoặc nghịch đảo của nó) mà không thực sự mã hóa cứng các codepoints, bằng cách sử dụng các danh mục chung Unicode. Một nghịch đảo có thể là một cái gì đó giống như [\ p {Cc} \ p {Cs} \ p {Cn}], ngoại trừ việc không đúng cách bao gồm các dòng và tab và bỏ sót một số ký tự không hợp lệ khác.

Trả lời

6

Đối với hệ thống lưu trữ nội bộ các điểm mã trong UTF-16, việc sử dụng cặp thay thế (xD800-xDFFF) cho điểm mã trên 0xFFFF và trong các hệ thống đó bạn phải xác minh xem bạn có thực sự sử dụng ví dụ \ u12345 hay không như một cặp thay thế. (Tôi vừa phát hiện ra rằng trong C# bạn có thể sử dụng \u1234 (16 bit) and \U000(32-bit))

Theo đề xuất của W3C không cho phép các ký tự thay thế bên trong tên phần tử hoặc thuộc tính. " Trong khi tìm kiếm trang web của W3 tôi tìm thấy C079C078 mà có thể bạn quan tâm.

+0

Mặc dù đây là mẹo triển khai hữu ích nhưng nó không thực sự trả lời câu hỏi của tôi. Chúng ta hãy giả định cho các đối số vì lợi ích của việc thực hiện có sự hỗ trợ tỷ lệ đầu tiên của các ký tự không phải BMP, vì vậy các ký tự thay thế là không cần thiết chút nào. –

67

Tôi biết điều này là không chính xác câu trả lời cho câu hỏi của bạn, nhưng nó rất hữu ích để có nó ở đây:

Regular Expression để phù hợp với hợp lệ Nhân vật XML:

[\u0009\u000a\u000d\u0020-\uD7FF\uE000-\uFFFD] 

Vì vậy, để loại bỏ không hợp lệ ký tự từ XML, bạn sẽ làm điều gì đó như

// filters control characters but allows only properly-formed surrogate sequences 
private static Regex _invalidXMLChars = new Regex(
    @"(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\uFEFF\uFFFE\uFFFF]", 
    RegexOptions.Compiled); 

/// <summary> 
/// removes any unusual unicode characters that can't be encoded into XML 
/// </summary> 
public static string RemoveInvalidXMLChars(string text) 
{ 
    if (string.IsNullOrEmpty(text)) return ""; 
    return _invalidXMLChars.Replace(text, ""); 
} 

Tôi đã có của chúng tôi thường trú regex/XML thiên tài, he of the 4,400+ upvoted post, kiểm tra này, và ông đã ký tắt trên đó.

+4

Thay vì text.IsNullOrEmpty() Tôi nghĩ rằng bạn cần string.IsNullOrEmpty (văn bản) –

+1

Bạn là Jeff Atwood, bạn không thực sự cần một cư dân bất cứ điều gì để đăng xuất về công cụ của bạn ở đây. – jbnunn

+8

Tôi khuyên bạn không nên bỏ các ký tự không hợp lệ, nhưng thay thế chúng bằng ký tự thay thế (FFFD). Tước các ký tự không hợp lệ làm cho việc gỡ rối khó khăn hơn (các vấn đề trở nên vô hình) và trong một số trường hợp, nó có thể dẫn đến các lỗ hổng bảo mật. –

4

tôi đã cố gắng này trong java và nó hoạt động:

private String filterContent(String content) { 
    return content.replaceAll("[^\\u0009\\u000a\\u000d\\u0020-\\uD7FF\\uE000-\\uFFFD]", ""); 
} 

Cảm ơn bạn Jeff.

+0

Giải pháp một dòng thanh lịch. Cảm ơn Yuval. – Dekel

1

Các giải pháp trên không hiệu quả đối với tôi nếu mã hex có trong xml. ví dụ.

<element>&#x8;</element>

Đoạn mã dưới đây sẽ phá vỡ:

string xmlFormat = "<element>{0}</element>"; 
string invalid = " &#x8;"; 
string xml = string.Format(xmlFormat, invalid); 
xml = Regex.Replace(xml, @"[\x01-\x08\x0B\x0C\x0E\x0F\u0000-\u0008\u000B\u000C\u000E-\u001F]", ""); 
XDocument.Parse(xml); 

Nó trả về:

XmlException: '', thập lục phân giá trị 0x08, là một nhân vật không hợp lệ. Dòng 1, vị trí 14.

Sau đây là regex được cải thiện và khắc phục vấn đề nêu trên:

& #x ([0-8BCEFbcef] | 1 [0-9A-Pháp-f]); | [\ x01- \ x08 \ x0B \ x0C \ x0E \ x0F \ u0000- \ u0008 \ u000B \ u000C \ u000E- \ u001F]

Dưới đây là một thử nghiệm đơn vị cho 300 ký tự unicode đầu tiên và xác nhận rằng chỉ các ký tự không hợp lệ bị xóa:

[Fact] 
     public void validate_that_RemoveInvalidData_only_remove_all_invalid_data() 
     { 
      string xmlFormat = "<element>{0}</element>"; 
      string[] allAscii = (Enumerable.Range('\x1', 300).Select(x => ((char)x).ToString()).ToArray()); 
      string[] allAsciiInHexCode = (Enumerable.Range('\x1', 300).Select(x => "&#x" + (x).ToString("X") + ";").ToArray()); 
      string[] allAsciiInHexCodeLoweCase = (Enumerable.Range('\x1', 300).Select(x => "&#x" + (x).ToString("x") + ";").ToArray()); 

      bool hasParserError = false; 
      IXmlSanitizer sanitizer = new XmlSanitizer(); 

      foreach (var test in allAscii.Concat(allAsciiInHexCode).Concat(allAsciiInHexCodeLoweCase)) 
      { 
       bool shouldBeRemoved = false; 
       string xml = string.Format(xmlFormat, test); 
       try 
       { 
        XDocument.Parse(xml); 
        shouldBeRemoved = false; 
       } 
       catch (Exception e) 
       { 
        if (test != "<" && test != "&") //these char are taken care of automatically by my convertor so don't need to test. You might need to add these. 
        { 
         shouldBeRemoved = true; 
        } 
       } 
       int xmlCurrentLength = xml.Length; 
       int xmlLengthAfterSanitize = Regex.Replace(xml, @"&#x([0-8BCEF]|1[0-9A-F]);|[\u0000-\u0008\u000B\u000C\u000E-\u001F]", "").Length; 
       if ((shouldBeRemoved && xmlCurrentLength == xmlLengthAfterSanitize) //it wasn't properly Removed 
        ||(!shouldBeRemoved && xmlCurrentLength != xmlLengthAfterSanitize)) //it was removed but shouldn't have been 
       { 
        hasParserError = true; 
        Console.WriteLine(test + xml); 
       } 
      } 
      Assert.Equal(false, hasParserError); 
     } 
0

Một cách khác để loại bỏ ký tự XML không chính xác trong C# với việc sử dụng XmlConvert.IsXmlChar Method (sẵn từ .NET Framework 4,0)

public static string RemoveInvalidXmlChars(string content) 
{ 
    return new string(content.Where(ch => System.Xml.XmlConvert.IsXmlChar(ch)).ToArray()); 
} 

hoặc bạn có thể kiểm tra xem tất cả các nhân vật XML hợp lệ.

public static bool CheckValidXmlChars(string content) 
{ 
    return content.All(ch => System.Xml.XmlConvert.IsXmlChar(ch)); 
} 

Net Fiddle - https://dotnetfiddle.net/v1TNus

Ví dụ, biểu tượng tab dọc (\ v) là không hợp lệ cho XML, nó có giá trị UTF-8, nhưng XML không hợp lệ 1.0, và thậm chí nhiều thư viện (bao gồm libxml2) bỏ lỡ nó và âm thầm xuất XML không hợp lệ.

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