在C#中转义无效的XML字符


83

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


2
您能否提供更多背景信息?样本输入和样本预期输出。另外,您打算如何处理输出。
Darin Dimitrov

5
您在编写XML吗?还是您正在尝试读取实际上不是XML的XML?
马克·格拉韦尔

3
使用XmlWriter,它将为您转义无效字符
Thomas Levesque

2
@alireza,如果您在评论中回答人们在问您的问题(以获取更多信息),您将获得更多有用的答案……
Marc Gravell

对不起。我离开了几个小时。请阅读导致这一问题的问题:stackoverflow.com/questions/8330619/…您将在那里获得所需的所有信息
Alireza Noori

Answers:


112

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

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


XmlConvert.VerifyXmlChars如果参数包含无效字符,则不会引发异常,它返回空字符串(如果所有包含的字符均有效,则返回参数)。试试吧return XmlConvert.VerifyXmlChars (text) != null
Matt Enright 2013年


3
@IgorKustov我不好!返回值文档似乎与此矛盾,谢谢您帮助我。
马特·恩赖特

3
如果该字符串用于XML值,请不要使用XmlConvert.EncodeName。XML名称限制比XML值限制更严格,名称编码将导致不必要的意外转义。
大卫·伯格

1
@arik我的代码仅用于演示目的,以显示转换前后XML字符串的状态。显然,您无需在代码中对其进行验证。
伊戈尔·库斯托夫

66

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

11
这不会转义控制字符(例如char 30)。
zimdanen

19

如果要编写xml,请仅使用框架提供的类来创建xml。您将不必为转义或任何事情而烦恼。

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

将输出

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

如果需要读取格式错误的XML文件,请不要 使用正则表达式。而是使用HTML Agility Pack


真好 对于使用XmlElement的人,您是否有等效的方法?
djdanlib 2011年

3
更新:设置XmlElement的InnerText属性似乎可以正确地进行转义。回答了我自己的问题,真主!
djdanlib 2011年

那么您的xml格式不正确?喜欢<Data>&</Data>吗?
Pierre-Alain Vigeant

2
是的,这就是问题所在。
Alireza Noori

2
如果元素的内容包含无效字符(例如退格键(0x08),许多其他控制字符或替代代码点),您仍然会遇到问题。
jakubiszon 2014年

6

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

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

    string newContent = RemoveInvalidXmlChars(content);

    Console.WriteLine(newContent);
}

这将返回一个空字符串,但不应返回!由于字符U + 10330是有效的XML字符,因此应返回“ \ U00010330” 。

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

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

4

这是上述方法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();

}

这是什么?.语法?符合result?.Append(ch);吗?
JB。和莫妮卡


1
// Replace invalid characters with empty strings.
   Regex.Replace(inputString, @"[^\w\.@-]", ""); 

正则表达式模式[^ \ w。@-]与不是单词字符,句点,@符号或连字符的任何字符匹配。单词字符是任何字母,十进制数字或标点连接符,例如下划线。与此模式匹配的任何字符都将由String.Empty替换,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;
        }
    }
}

0
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)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.