首页 文章

转义C#中的无效XML字符

提问于
浏览
64

我有一个包含无效XML字符的字符串 . 在解析字符串之前,如何转义(或删除)无效的XML字符?

6 回答

  • 19

    作为删除无效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;
        }
    }
    

    Update: 应该提到的是,编码操作产生的字符串的长度大于或等于源字符串的长度 . 将编码字符串存储在具有长度限制的字符串列中的数据库中并在应用程序中验证源字符串长度以适应数据列限制时,这可能很重要 .

  • 0

    使用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);
      }
    }
    
  • 90

    如果您正在编写xml,只需使用框架提供的类来创建xml . 你不必为逃避或任何事情而烦恼 .

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

    会输出

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

    如果需要读取格式错误的XML文件,请执行 do not use正则表达式 . 而是使用Html Agility Pack .

  • 3

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

    以下是上述方法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();
    
        }
    
  • 4
    // Replace invalid characters with empty strings.
       Regex.Replace(inputString, @"[^\w\.@-]", "");
    

    正则表达式模式[^\ w . @ -]匹配任何不是单词字符,句点,@符号或连字符的字符 . 单词字符是任何字母,十进制数字或标点符号连接符,例如下划线 . 匹配此模式的任何字符都将替换为String.Empty,它是替换模式定义的字符串 . 要允许用户输入中的其他字符,请将这些字符添加到正则表达式模式中的字符类中 . 例如,正则表达式模式[^\ w . @ - \%]也允许输入字符串中的百分比符号和反斜杠 .

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

    请参考这个:

    Removing Invalid Characters from XML Name Tag - 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;
            }
        }
    }
    

相关问题