2012-10-17 14 views
7

Wir sammeln viele Zeichenfolgen und senden sie an unsere Kunden in XML-Fragmenten. Diese Zeichenfolgen können buchstäblich jedes Zeichen enthalten. Beim Versuch, XElement-Instanzen mit "schlechten" Zeichen zu serialisieren, ist ein Fehler aufgetreten. Hier ein Beispiel:Behandeln von Zeichenfolgen zum Einfügen in 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 

Der obige Code generiert eine Ausnahme an der angegebenen Zeile. Hier ist der 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) 

Mein Verdacht ist, dass dies nicht das richtige Verhalten und die schlechten Zeichen sollten in die XML entwertet werden. Ob dies wünschenswert ist oder nicht, ist eine Frage, die ich später beantworten werde.

Also hier ist die Frage:

Gibt es eine Möglichkeit Strings behandeln, so dass dieser Fehler auftreten kann, nicht, oder sollte ich einfach alle Zeichen Streifen unter char 0x20 und meine Finger kreuzen?

+0

Gute Frage. Eigentlich sollten Sie * alle * Zeichen unterhalb von 0x20 nicht entfernen, da einige von ihnen ordnungsgemäß maskiert sind (z. B. CR, LF, TAB ...). Aber ich kann keinen Grund sehen, warum die anderen nicht entkommen können ... –

+0

Werden Ihre Kunden jemals diese Zeichen in den Strings brauchen? – climbage

+0

Nein. Definitiv nicht. Sie werden entweder in einem WPF-Textfeld oder als mvcstring in einer Webanwendung gerendert. In unserem Fall könnten sogar @ThomasLevesques cr/lf/tab-Combos entfernt werden, weil wir eine einzelne Zeile erwarten. Diese Strings sind eine echte Reise zu unseren Servern über IDV3-Tags, Broadcasting-Software und Shoutcast-Server. Es ist gut möglich, dass Codierungen auf dem Weg herumgemistet wurden. Ich denke, dass meine Lösung für uns völlig anwendbar ist. Ich bin immer noch verwirrt von dieser Ausnahme und möchte bestätigen, dass ich einen Fehler in .net entdeckt habe. – spender

Antwort

5

Dies ist, was ich in meinem Code verwende:

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

Alle Zeichen unten 0x20 (außer \ n \ t \ r) durch ihren XML-Unicode-Codes ersetzt werden: 0x1f => "& # 001F" . Der Xml-Parser sollte die Datei beim Lesen der Datei automatisch auf 0x1f zurücksetzen. Verwenden Sie einfach neue XAttribute ("Attribut", Fix (yourString))

Es funktioniert für XElement Inhalt a es sollte wahrscheinlich auch für XAttributes funktionieren.

+0

Mit etwas ähnlichem behoben. Mangels einer zwingenden Antwort gebe ich dir die Punkte. – spender

8

Ein wenig mit ILSpy graben ergab, dass man das XmlWriter/ReaderSettings.CheckCharacters Feld verwenden kann, um zu steuern, ob eine Ausnahme für ungültige Zeichen ausgelöst wird. Angelehnt an der XNode.ToString-Methode und die XDocument.Parse Methode habe ich mit den folgenden Beispielen kommen:

Um stringify ein XLinq Objekt mit ungültigen (Kontrolle) Zeichen:

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

eine parsen XLinq-Objekt mit ungültigen Zeichen:

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); 
    } 
} 
+0

Ausgezeichnet, vielen Dank. –

Verwandte Themen