C# 处理字符串以插入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

我们收集了大量字符串,并将它们以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", 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);
    }
}