Tôi có một chuỗi chứa các ký tự XML không hợp lệ. Làm cách nào để thoát (hoặc xóa) các ký tự XML không hợp lệ trước khi tôi phân tích cú pháp chuỗi?
Tôi có một chuỗi chứa các ký tự XML không hợp lệ. Làm cách nào để thoát (hoặc xóa) các ký tự XML không hợp lệ trước khi tôi phân tích cú pháp chuỗi?
Câu trả lời:
Để loại bỏ các ký tự XML không hợp lệ, tôi khuyên bạn nên sử dụng phương thức XmlConvert.IsXmlChar . Nó đã được thêm vào từ .NET Framework 4 và cũng được trình bày trong Silverlight. Đây là mẫu nhỏ:
void Main() {
string content = "\v\f\0";
Console.WriteLine(IsValidXmlString(content)); // False
content = RemoveInvalidXmlChars(content);
Console.WriteLine(IsValidXmlString(content)); // True
}
static string RemoveInvalidXmlChars(string text) {
var validXmlChars = text.Where(ch => XmlConvert.IsXmlChar(ch)).ToArray();
return new string(validXmlChars);
}
static bool IsValidXmlString(string text) {
try {
XmlConvert.VerifyXmlChars(text);
return true;
} catch {
return false;
}
}
Và là cách để thoát các ký tự XML không hợp lệ, tôi khuyên bạn nên sử dụng phương thức XmlConvert.EncodeName . Đây là mẫu nhỏ:
void Main() {
const string content = "\v\f\0";
Console.WriteLine(IsValidXmlString(content)); // False
string encoded = XmlConvert.EncodeName(content);
Console.WriteLine(IsValidXmlString(encoded)); // True
string decoded = XmlConvert.DecodeName(encoded);
Console.WriteLine(content == decoded); // True
}
static bool IsValidXmlString(string text) {
try {
XmlConvert.VerifyXmlChars(text);
return true;
} catch {
return false;
}
}
Cập nhật: Cần lưu ý rằng hoạt động mã hóa tạo ra một chuỗi có độ dài lớn hơn hoặc bằng độ dài của chuỗi nguồn. Điều này có thể quan trọng khi bạn lưu trữ một chuỗi được mã hóa trong cơ sở dữ liệu trong cột chuỗi có giới hạn độ dài và xác thực độ dài chuỗi nguồn trong ứng dụng của bạn để phù hợp với giới hạn cột dữ liệu.
XmlConvert.VerifyXmlChars
không ném ra ngoại lệ nếu đối số chứa các ký tự không hợp lệ, nó trả về chuỗi null (và trả về đối số nếu tất cả các ký tự được chứa đều hợp lệ). Hãy thử chỉ return XmlConvert.VerifyXmlChars (text) != null
.
Sử dụng SecurityElement.Escape
using System;
using System.Security;
class Sample {
static void Main() {
string text = "Escape characters : < > & \" \'";
string xmlText = SecurityElement.Escape(text);
//output:
//Escape characters : < > & " '
Console.WriteLine(xmlText);
}
}
Nếu bạn đang viết xml, chỉ cần sử dụng các lớp được cung cấp bởi khung công tác để tạo xml. Bạn sẽ không phải bận tâm đến việc trốn thoát hay bất cứ thứ gì.
Console.Write(new XElement("Data", "< > &"));
Sẽ xuất
<Data>< > &</Data>
Nếu bạn cần đọc tệp XML không đúng định dạng, không sử dụng biểu thức chính quy. Thay vào đó, hãy sử dụng Gói Nhanh nhẹn Html .
<Data>&</Data>
nào?
Phương thức RemoveInvalidXmlChars do Irishman cung cấp không hỗ trợ các ký tự thay thế. Để kiểm tra nó, hãy sử dụng ví dụ sau:
static void Main()
{
const string content = "\v\U00010330";
string newContent = RemoveInvalidXmlChars(content);
Console.WriteLine(newContent);
}
Điều này trả về một chuỗi trống nhưng nó không nên! Nó phải trả về "\ U00010330" vì ký tự U + 10330 là một ký tự XML hợp lệ.
Để hỗ trợ các ký tự thay thế, tôi khuyên bạn nên sử dụng phương pháp sau:
public static string RemoveInvalidXmlChars(string text)
{
if (string.IsNullOrEmpty(text))
return text;
int length = text.Length;
StringBuilder stringBuilder = new StringBuilder(length);
for (int i = 0; i < length; ++i)
{
if (XmlConvert.IsXmlChar(text[i]))
{
stringBuilder.Append(text[i]);
}
else if (i + 1 < length && XmlConvert.IsXmlSurrogatePair(text[i + 1], text[i]))
{
stringBuilder.Append(text[i]);
stringBuilder.Append(text[i + 1]);
++i;
}
}
return stringBuilder.ToString();
}
Đây là phiên bản được tối ưu hóa của phương thức RemoveInvalidXmlChars ở trên, phương thức này không tạo một mảng mới trong mỗi lần gọi, do đó nhấn mạnh GC một cách không cần thiết:
public static string RemoveInvalidXmlChars(string text)
{
if (text == null)
return text;
if (text.Length == 0)
return text;
// a bit complicated, but avoids memory usage if not necessary
StringBuilder result = null;
for (int i = 0; i < text.Length; i++)
{
var ch = text[i];
if (XmlConvert.IsXmlChar(ch))
{
result?.Append(ch);
}
else if (result == null)
{
result = new StringBuilder();
result.Append(text.Substring(0, i));
}
}
if (result == null)
return text; // no invalid xml chars detected - return original text
else
return result.ToString();
}
?.
Cú pháp này là gì? trong hàng result?.Append(ch);
?
// Replace invalid characters with empty strings.
Regex.Replace(inputString, @"[^\w\.@-]", "");
Mẫu biểu thức chính quy [^ \ w. @ -] khớp với bất kỳ ký tự nào không phải là ký tự từ, dấu chấm, ký hiệu @ hoặc dấu gạch ngang. Một ký tự từ là bất kỳ ký tự nào, chữ số thập phân hoặc kết nối dấu câu, chẳng hạn như dấu gạch dưới. Bất kỳ ký tự nào phù hợp với mẫu này sẽ được thay thế bằng String.Empty, là chuỗi được xác định bởi mẫu thay thế. Để cho phép các ký tự bổ sung trong dữ liệu nhập của người dùng, hãy thêm các ký tự đó vào lớp ký tự trong mẫu biểu thức chính quy. Ví dụ: mẫu biểu thức chính quy [^ \ w. @ - \%] cũng cho phép ký hiệu tỷ lệ phần trăm và dấu gạch chéo ngược trong chuỗi nhập.
Regex.Replace(inputString, @"[!@#$%_]", "");
Tham khảo thêm cái này:
Xóa các ký tự không hợp lệ khỏi thẻ tên XML - RegEx C #
Đây là một hàm để xóa các ký tự khỏi một chuỗi XML được chỉ định:
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace XMLUtils
{
class Standards
{
/// <summary>
/// Strips non-printable ascii characters
/// Refer to http://www.w3.org/TR/xml11/#charsets for XML 1.1
/// Refer to http://www.w3.org/TR/2006/REC-xml-20060816/#charsets for XML 1.0
/// </summary>
/// <param name="content">contents</param>
/// <param name="XMLVersion">XML Specification to use. Can be 1.0 or 1.1</param>
private void StripIllegalXMLChars(string tmpContents, string XMLVersion)
{
string pattern = String.Empty;
switch (XMLVersion)
{
case "1.0":
pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|7F|8[0-46-9A-F]9[0-9A-F])";
break;
case "1.1":
pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|[19][0-9A-F]|7F|8[0-46-9A-F]|0?[1-8BCEF])";
break;
default:
throw new Exception("Error: Invalid XML Version!");
}
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
if (regex.IsMatch(tmpContents))
{
tmpContents = regex.Replace(tmpContents, String.Empty);
}
tmpContents = string.Empty;
}
}
}
string XMLWriteStringWithoutIllegalCharacters(string UnfilteredString)
{
if (UnfilteredString == null)
return string.Empty;
return XmlConvert.EncodeName(UnfilteredString);
}
string XMLReadStringWithoutIllegalCharacters(string FilteredString)
{
if (UnfilteredString == null)
return string.Empty;
return XmlConvert.DecodeName(UnfilteredString);
}
Phương pháp đơn giản này thay thế các ký tự không hợp lệ bằng cùng một giá trị nhưng được chấp nhận trong ngữ cảnh XML.
Để viết chuỗi, hãy sử dụng XMLWriteStringWithoutIllegalCharacters (chuỗi UnfilteredString).
Để đọc chuỗi, hãy sử dụng XMLReadStringWithoutIllegalCharacters (chuỗi FilteredString).