通过在反序列化之前添加预处理步骤,使用 RestSharp 处理 XML 中的无效字符

Handling invalid characters in XML with RestSharp by adding a pre-processing step before deserialization

我正在使用 RestSharp 库使用 Web 服务。我无法控制 Web 服务的实现,因为它是第三方 (Taleo Business Edition)。

我的问题是有些错误数据包含无效字符。这些数据中有很多 copy/pasted 来自文档,我不能强迫用户返回并清理这些数据。坏字符是不可见的控制代码 (0x01) 也于事无补。

我能想到的唯一解决方案是在 RestSharp 尝试反序列化 XML 之前添加一个预处理步骤。我真的很想避免编写自己的 XML 解串器。

我考虑过扩展 XmlSerializer class,但似乎没有任何虚拟方法可用于添加此预处理步骤。

我也看过尝试使用 RestSharp 库中的 OnBeforeDeserializing 事件,但我不知道我可以在那里做些什么来预处理 XML。

我觉得我在这里遗漏了一些基本的东西,因为它似乎是使用 RESTful 网络服务的常见用例。

我认为你在 OnBeforeDeserializing 方面进展顺利。

怎么样:

request.OnBeforeDeserialization = resp =>
{
   // here, resp.Content is the xml in string. Just erase the invalid characters
   // resp.Content = resp.Content.Replace(..., "")          
};

不幸的是,使用 OnBeforeDeserialization 不允许您预处理内容。当您在此处修改 ContentRawBytes 属性时,它们实际上并没有改变。这解释了为什么 none 的正则表达式解决方案在尝试清理我的 XML.

时似乎有任何效果

为了修改内容,您必须使用自定义 XML 反序列化器。幸运的是,这比我想象的要容易,因为您可以扩展 RestSharp.Deserializers.XmlDeserializer 并覆盖 Deserialize<T> 方法。然后,您可以在将 response.Content 传递给基本函数之前对其进行修改。


我最终使用的解决方案:

class CustomXmlDeserializer : RestSharp.Deserializers.XmlDeserializer {
    public override T Deserialize<T>(IRestResponse response) {
        //string pattern = @"&#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|7F|8[0-46-9A-F]9[0-9A-F])"; // XML 1.0
        string pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|[19][0-9A-F]|7F|8[0-46-9A-F]|0?[1-8BCEF])"; // XML 1.1
        System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        if (regex.IsMatch(response.Content)) {
            response.Content = regex.Replace(response.Content, String.Empty);
        }
        response.Content = response.Content.Replace("&;", string.Empty);

        return base.Deserialize<T>(response);
    }
}

基于这个答案:


我的主要问题是文档中有一大堆无效的 xml 实体 。我从未见过任何实际的无效控制代码字符。但是我有很多像 &#x0;&#x4 之类的东西。这意味着我无法使用仅对特定字符值进行转义的解决方案。

当我尝试在 OnBeforeDeserialize 中使用上面的正则表达式时,它似乎根本不起作用。问题实际上不是正则表达式,而是你不能在那里修改 Content 属性 的事实。

此解决方案对其他人来说可能过于本地化,但您应该能够在此处修改预处理代码以获得所需的结果。

这个解决方案帮助了我。在将响应传递给 DotNetXmlDeserializer 之前必须替换特殊字符`

string filtered_resp = response.Content;
if (filtered_resp.Contains("&"))
    {

      filtered_resp = response.Content.Replace("&", string.Empty);
           
    }            
RestResponse modified_response = new RestResponse { Content = filtered_resp };
return DotNetXmlDeserializer.Deserialize<T>(modified_response);