通过在反序列化之前添加预处理步骤,使用 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
不允许您预处理内容。当您在此处修改 Content
或 RawBytes
属性时,它们实际上并没有改变。这解释了为什么 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 实体 。我从未见过任何实际的无效控制代码字符。但是我有很多像 �
和 
之类的东西。这意味着我无法使用仅对特定字符值进行转义的解决方案。
当我尝试在 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);
我正在使用 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
不允许您预处理内容。当您在此处修改 Content
或 RawBytes
属性时,它们实际上并没有改变。这解释了为什么 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 实体 。我从未见过任何实际的无效控制代码字符。但是我有很多像 �
和 
之类的东西。这意味着我无法使用仅对特定字符值进行转义的解决方案。
当我尝试在 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);