簡體   English   中英

在 C# 中轉義無效的 XML 字符

[英]Escape invalid XML characters in C#

我有一個包含無效 XML 字符的字符串。 在解析字符串之前,如何轉義(或刪除)無效的 XML 字符?

作為刪除無效 XML 字符的方法,我建議您使用XmlConvert.IsXmlChar方法。 它是從 .NET Framework 4 開始添加的,並且也出現在 Silverlight 中。 這是小樣本:

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

作為轉義無效 XML 字符的方法,我建議您使用XmlConvert.EncodeName方法。 這是小樣本:

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

更新:應該提到的是,編碼操作會產生一個長度大於或等於源字符串長度的字符串。 當您將編碼字符串存儲在具有長度限制的字符串列中的數據庫中並驗證應用程序中的源字符串長度以適應數據列限制時,這可能很重要。

使用SecurityElement.Escape

using System;
using System.Security;

class Sample {
  static void Main() {
    string text = "Escape characters : < > & \" \'";
    string xmlText = SecurityElement.Escape(text);
//output:
//Escape characters : &lt; &gt; &amp; &quot; &apos;
    Console.WriteLine(xmlText);
  }
}

如果你正在編寫xml,只需使用框架提供的類來創建xml。 你不必費心逃避或任何事情。

Console.Write(new XElement("Data", "< > &"));

會輸出

<Data>&lt; &gt; &amp;</Data>

如果您需要讀取格式錯誤的 XML 文件,請不要使用正則表達式。 相反,請使用Html Agility Pack

這是上述方法 RemoveInvalidXmlChars 的優化版本,它不會在每次調用時創建新數組,從而不必要地強調 GC:

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

}

Irishman 提供的 RemoveInvalidXmlChars 方法不支持代理字符。 要測試它,請使用以下示例:

static void Main()
{
    const string content = "\v\U00010330";

    string newContent = RemoveInvalidXmlChars(content);

    Console.WriteLine(newContent);
}

這將返回一個空字符串,但它不應該! 它應該返回“\\U00010330”,因為字符U+10330是一個有效的 XML 字符。

為了支持代理字符,我建議使用以下方法:

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();
}
// Replace invalid characters with empty strings.
   Regex.Replace(inputString, @"[^\w\.@-]", ""); 

正則表達式模式 [^\\w.@-] 匹配任何不是單詞字符、句點、@ 符號或連字符的字符。 單詞字符是任何字母、十進制數字或標點符號(例如下划線)。 任何與此模式匹配的字符都將替換為 String.Empty,后者是由替換模式定義的字符串。 要允許用戶輸入中的其他字符,請將這些字符添加到正則表達式模式中的字符類。 例如,正則表達式模式 [^\\w.@-\\%] 還允許在輸入字符串中使用百分比符號和反斜杠。

Regex.Replace(inputString, @"[!@#$%_]", "");

也參考這個:

從 XML 名稱標簽中刪除無效字符 - RegEx C#

這是一個從指定的 XML 字符串中刪除字符的函數:

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

這個簡單的方法用相同的值替換無效字符,但在 XML 上下文中被接受。


要寫入字符串,請使用 XMLWriteStringWithoutIllegalCharacters(string UnfilteredString)。
要讀取字符串,請使用 XMLReadStringWithoutIllegalCharacters(string FilteredString)。

如果您只是為在 XML 標記內使用的字符串轉義無效的 XML 字符,則可以執行類似這樣的簡單操作。

這在您不使用 XML 庫時有效。

public string EscapeXMLCharacters (string target)
{
    return
        target
            .Replace("&", "&amp;")
            .Replace("<", "&lt;")
            .Replace(">", "&gt;")
            .Replace("\"", "&quot;")
            .Replace("'", "&apos;");
}

然后你可以這樣稱呼它:

public string GetXMLBody(string content)
{
    return @"<input>" + EscapeXMLCharacters(content) + "</input>";
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM