在构造使用该数据的XmlReader或者XPathDocument之前,如何从基于XML的数据源中删除无效的十六进制字符?

时间:2020-03-05 18:41:42  来源:igfitidea点击:

在XmlReader中使用它之前,是否有任何简单/通用的方法来清理基于XML的数据源,以便我可以正常使用不符合XML十六进制字符限制的XML数据?

笔记:

  • 该解决方案需要处理使用UTF-8以外的字符编码的XML数据源,例如通过在XML文档声明中指定字符编码。剥离无效的十六进制字符时不破坏源代码的字符编码一直是主要的问题。
  • 删除无效的十六进制字符仅应删除十六进制编码的值,因为我们经常会在数据中恰好包含一个与十六进制字符匹配的字符串的数据中找到href值。

背景:

我需要使用符合特定格式(例如Atom或者RSS提要)的基于XML的数据源,但希望能够使用已发布的数据源(根据XML规范包含无效的十六进制字符)。

在.NET中,如果我们有一个表示XML数据源的Stream,然后尝试使用XmlReader和/或者XPathDocument对其进行解析,则会由于XML数据中包含无效的十六进制字符而引发异常。我当前解决此问题的尝试是将Stream解析为字符串,并使用正则表达式删除和/或者替换无效的十六进制字符,但是我正在寻找一种性能更高的解决方案。

解决方案

回答

这可能并不完美(由于人们错过了此免责声明,因此添加了重点),但在此情况下,我的工作如下。我们可以调整以与流一起使用。

/// <summary>
/// Removes control characters and other non-UTF-8 characters
/// </summary>
/// <param name="inString">The string to process</param>
/// <returns>A string with no control characters or entities above 0x00FD</returns>
public static string RemoveTroublesomeCharacters(string inString)
{
    if (inString == null) return null;

    StringBuilder newString = new StringBuilder();
    char ch;

    for (int i = 0; i < inString.Length; i++)
    {

        ch = inString[i];
        // remove any characters outside the valid UTF-8 range as well as all control characters
        // except tabs and new lines
        //if ((ch < 0x00FD && ch > 0x001F) || ch == '\t' || ch == '\n' || ch == '\r')
        //if using .NET version prior to 4, use above logic
        if (XmlConvert.IsXmlChar(ch)) //this method is new in .NET 4
        {
            newString.Append(ch);
        }
    }
    return newString.ToString();

}

回答

我喜欢尤金的白名单概念。我需要做与原始海报类似的操作,但是我需要支持所有Unicode字符,而不仅仅是0x00FD。 XML规范是:

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

在.NET中,Unicode字符的内部表示形式只有16位,因此我们不能明确地"允许" 0x10000-0x10FFFF。 XML规范明确禁止出现从0xD800开始的替代代码点。但是,如果我们允许在白名单中使用这些替代代码点,则只要字符串中的utf-16字符替代对产生了正确的utf-8编码,我们的字符串utf-8编码最终就可以产生有效的XML。 .NET字符串。不过,我还没有对此进行探讨,因此我选择了比较安全的选择,并且不允许将替代产品列入我的白名单。

不过,尤金解决方案中的注释具有误导性,问题在于我们排除的字符在XML中无效……它们是完全有效的Unicode代码点。我们不会删除"非UTF-8字符"。我们将删除格式不正确的XML文档中可能不会出现的utf-8字符。

public static string XmlCharacterWhitelist( string in_string ) {
    if( in_string == null ) return null;

    StringBuilder sbOutput = new StringBuilder();
    char ch;

    for( int i = 0; i < in_string.Length; i++ ) {
        ch = in_string[i];
        if( ( ch >= 0x0020 && ch <= 0xD7FF ) || 
            ( ch >= 0xE000 && ch <= 0xFFFD ) ||
            ch == 0x0009 ||
            ch == 0x000A || 
            ch == 0x000D ) {
            sbOutput.Append( ch );
        }
    }
    return sbOutput.ToString();
}

回答

private static String removeNonUtf8CompliantCharacters( final String inString ) {
    if (null == inString ) return null;
    byte[] byteArr = inString.getBytes();
    for ( int i=0; i < byteArr.length; i++ ) {
        byte ch= byteArr[i]; 
        // remove any characters outside the valid UTF-8 range as well as all control characters
        // except tabs and new lines
        if ( !( (ch > 31 && ch < 253 ) || ch == '\t' || ch == '\n' || ch == '\r') ) {
            byteArr[i]=' ';
        }
    }
    return new String( byteArr );
}

回答

试试这个PHP!

$goodUTF8 = iconv("utf-8", "utf-8//IGNORE", $badUTF8);