8

多くの文字列を収集し、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

上記のコードは、示された行で例外を生成します。スタックトレースは次のとおりです。

「SUB」、16 ​​進値 0x1A は無効な文字です。System.ArgumentException System.ArgumentException: ''、16 進値 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.WriteStartElement (XElement e) で
   System.Xml.Linq.ElementWriter.WriteElement (XElement e) で
   System.Xml.Linq.XElement.WriteTo (XmlWriter ライター) で
   System.Xml.Linq.XNode.GetXmlString (SaveOptions o) で

私の疑いでは、これは正しい動作ではなく、不正な文字は XML にエスケープする必要があります。これが望ましいかどうかは、後で答える質問です。

だからここに質問があります:

このエラーが発生しないように文字列を処理する方法はありますか、それとも char の下のすべての文字を単純に削除し0x20て指を交差させる必要がありますか?

4

2 に答える 2

9

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();
}

無効な文字を含む XLinq オブジェクトを解析するには:

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);
    }
}
于 2013-02-13T02:18:17.730 に答える
6

これは私が私のコードで使用しているものです:

    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;
    }

0x20以下のすべての文字(\ r \ n \ tを除く)は、XMLユニコードコード0x1f => "&#001f"に置き換えられます。Xmlパーサーは、ファイルを読み取るときに自動的にエスケープを解除して0x1fに戻す必要があります。new XAttribute( "attribute"、Fix(yourString))を使用するだけです

XElementコンテンツで機能し、おそらくXAttributesでも機能するはずです。

于 2012-10-18T09:30:50.987 に答える