C# 处理字符串以插入XElement
我们收集了大量字符串,并将它们以xml片段的形式发送给客户机。这些字符串可以包含任何字符。我们看到一个错误,它是由于试图序列化包含“坏”字符的XElement实例而导致的。下面是一个例子:C# 处理字符串以插入XElement,c#,string,xelement,C#,String,Xelement,我们收集了大量字符串,并将它们以xml片段的形式发送给客户机。这些字符串可以包含任何字符。我们看到一个错误,它是由于试图序列化包含“坏”字符的XElement实例而导致的。下面是一个例子: var message = new XElement("song"); char c = (char)0x1a; //sub var someData = string.Format("some{0}stuff", c); var attr = new XAttribute("someAttr", someD
var message = new XElement("song");
char c = (char)0x1a; //sub
var someData = string.Format("some{0}stuff", c);
var attr = new XAttribute("someAttr", someData);
message.Add(attr);
string msgStr = message.ToString(SaveOptions.DisableFormatting); //exception here
上面的代码在指定行生成异常。这是stacktrace:
'SUB', hexadecimal value 0x1A, is an invalid character. System.ArgumentException System.ArgumentException: '', hexadecimal value 0x1A, is an invalid character.
at System.Xml.XmlEncodedRawTextWriter.InvalidXmlChar(Int32 ch, Char* pDst, Boolean entitize)
at System.Xml.XmlEncodedRawTextWriter.WriteAttributeTextBlock(Char* pSrc, Char* pSrcEnd)
at System.Xml.XmlEncodedRawTextWriter.WriteString(String text)
at System.Xml.XmlWellFormedWriter.WriteString(String text)
at System.Xml.XmlWriter.WriteAttributeString(String prefix, String localName, String ns, String value)
at System.Xml.Linq.ElementWriter.WriteStartElement(XElement e)
at System.Xml.Linq.ElementWriter.WriteElement(XElement e)
at System.Xml.Linq.XElement.WriteTo(XmlWriter writer)
at System.Xml.Linq.XNode.GetXmlString(SaveOptions o)
“SUB”(十六进制值0x1A)是无效字符。System.ArgumentException System.ArgumentException:'',十六进制值0x1A,是无效字符。
在System.Xml.XmlEncodedRawTextWriter.InvalidXmlChar(Int32 ch,Char*pDst,布尔实体化)
在System.Xml.XmlEncodedRawTextWriter.WriteAttributeTextBlock(Char*pSrc,Char*pSrcEnd)
位于System.Xml.XmlEncodedRawTextWriter.WriteString(字符串文本)
位于System.Xml.XmlWellFormedWriter.WriteString(字符串文本)
位于System.Xml.XmlWriter.WriteAttributeString(字符串前缀、字符串localName、字符串ns、字符串值)
位于System.Xml.Linq.ElementWriter.WriteStarteElement(XElement e)
位于System.Xml.Linq.ElementWriter.WriteElement(XElement e)
位于System.Xml.Linq.XElement.WriteTo(XmlWriter)
位于System.Xml.Linq.XNode.GetXmlString(SaveOptions)
我怀疑这不是正确的行为,应该将坏字符转义到XML中。这是否可取,我稍后会回答
所以问题是:
是否有某种方法处理字符串以避免出现此错误,或者我是否应该简单地去掉char
0x20
下面的所有字符并祈祷?这就是我在代码中使用的内容:
static Lazy<Regex> ControlChars = new Lazy<Regex>(() => new Regex("[\x00-\x1f]", RegexOptions.Compiled));
private static string FixData_Replace(Match match)
{
if ((match.Value.Equals("\t")) || (match.Value.Equals("\n")) || (match.Value.Equals("\r")))
return match.Value;
return "&#" + ((int)match.Value[0]).ToString("X4") + ";";
}
public static string Fix(object data, MatchEvaluator replacer = null)
{
if (data == null) return null;
string fixed_data;
if (replacer != null) fixed_data = ControlChars.Value.Replace(data.ToString(), replacer);
else fixed_data = ControlChars.Value.Replace(data.ToString(), FixData_Replace);
return fixed_data;
}
staticlazycontrolchars=newlazy(()=>newregex(“[\x00-\x1f]”,RegexOptions.Compiled));
私有静态字符串FixData_Replace(匹配)
{
if((match.Value.Equals(“\t”))|(match.Value.Equals(“\n”))|(match.Value.Equals(“\r”))
返回match.Value;
返回“”+((int)match.Value[0]).ToString(“X4”)+“;”;
}
公共静态字符串修复(对象数据,MatchEvaluator replacer=null)
{
if(data==null)返回null;
字符串固定数据;
if(replacer!=null)修复了_data=ControlChars.Value.Replace(data.ToString(),replacer);
else fixed_data=ControlChars.Value.Replace(data.ToString(),FixData_Replace);
返回固定数据;
}
0x20以下的所有字符(除\r\n\t外)将替换为其XML unicode代码:0x1f=>“f”。
当读取文件时,Xml解析器应该自动将其调回0x1f。
只需使用新的XAttribute(“attribute”,Fix(yourString))
它适用于XElement内容a它可能也适用于XAttributes。对ILSpy的一点挖掘表明,可以使用XmlWriter/ReaderSettings.CheckCharacters字段来控制是否为无效字符引发异常。借用XNode.ToString方法和XDocument.Parse方法,我给出了以下示例: 要使用无效(控制)字符字符串化XLinq对象,请执行以下操作:
XDocument xdoc = XDocument.Parse("<root>foo</root>");
using (StringWriter stringWriter = new StringWriter())
{
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings { OmitXmlDeclaration = true, CheckCharacters = false };
using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, xmlWriterSettings))
{
xdoc.WriteTo(xmlWriter);
}
return stringWriter.ToString();
}
好问题。实际上,您不应该删除0x20以下的所有字符,因为其中一些字符已正确转义(例如CR、LF、TAB…)。但是我看不出为什么其他字符没有被转义…你的客户会真的需要字符串中的字符吗?不,绝对不会。它们要么呈现到WPF文本框中,要么呈现为webapp中的mvcstring。事实上,在我们的例子中,甚至@ThomasLevesque的cr/lf/tab组合也可能被剥离,因为我们只需要一行。这些字符串通过idv3标签、广播软件和shoutcast服务器,在我们的服务器上进行了相当长的一段旅程。很有可能编码在过程中被破坏了。我认为我的解决方案完全适用于我们。我仍然对这个异常感到困惑,并希望确认我似乎在.net.Fixed中发现了一个类似的bug。由于没有一个更令人信服的答案,我将给你分。
XDocument xdoc;
using (StringReader stringReader = new StringReader(text))
{
XmlReaderSettings xmlReaderSettings = new XmlReaderSettings { CheckCharacters = false, DtdProcessing = DtdProcessing.Parse, MaxCharactersFromEntities = 10000000L, XmlResolver = null };
using (XmlReader xmlReader = XmlReader.Create(stringReader, xmlReaderSettings))
{
xdoc = XDocument.Load(xmlReader);
}
}