我使用ADO.NET从SQL Server投射一些数据作为XML。我的一些数据包含XML中无效的字符,例如CHAR(7)
(称为BEL
)。
SELECT 'This is BEL: ' + CHAR(7) AS A FOR XML RAW
SQL Server encodes这样的无效字符如数字引用:
<row A="This is BEL: " />
但是,即使编码的表单在XML 1.0下也是无效的,并且会在XML解析器中引起错误:
var doc = XDocument.Parse("<row A=\"This is BEL: \" />");
// XmlException: ' ', hexadecimal value 0x07, is an invalid character. Line 1, position 25.
我想用Unicode替换字符'�'
替换所有这些无效的数字引用。我知道如何为未编码的XML执行此操作:
string str = "<row A=\"This is BEL: \u0007\" />";
if (str.Any(c => !XmlConvert.IsXmlChar(c)))
str = new string(str.Select(c => XmlConvert.IsXmlChar(c) ? c : '�').ToArray());
// <row A="This is BEL: �" />
是否有一种简单的方法可以使其适用于编码的XML?我宁愿避免使用HtmlDecode
然后HtmlEncode
整个字符串,以免冒险引入除无效字符替换之外的更改。
编辑:转换需要在我的C#代码中完成,而不是SQL,以便集中实现。
答案 0 :(得分:2)
我使用正则表达式再次使用它。这应该处理十进制和十六进制字符代码。此外,除了数字编码的字符外,这不会影响任何内容。
public string ReplaceXMLEncodedCharacters(string input)
{
const string pattern = @"&#(x?)([A-Fa-f0-9]+);";
MatchCollection matches = Regex.Matches(input, pattern);
int offset = 0;
foreach (Match match in matches)
{
int charCode = 0;
if (string.IsNullOrEmpty(match.Groups[1].Value))
charCode = int.Parse(match.Groups[2].Value);
else
charCode = int.Parse(match.Groups[2].Value, System.Globalization.NumberStyles.HexNumber);
char character = (char)charCode;
input = input.Remove(match.Index - offset, match.Length).Insert(match.Index - offset, character.ToString());
offset += match.Length - 1;
}
return input;
}
答案 1 :(得分:1)
您可以将特殊字符包装在CDATA tag中。这会通知解析器忽略标记内的文本。要使用您的示例:
SELECT 'This is BEL: <![CDATA[' + CHAR(7) + ']]>' AS A FOR XML RAW
这将允许至少解析XML,尽管需要对文档结构稍作修改。
答案 2 :(得分:0)
供参考,这是我的解决方案。我建立在Tonkleton's answer之上,但修改它以更紧密地匹配hash
的内部实现。下面的代码忽略了代理对。
HtmlDecode