Wieder mal habe ich Probleme mit XML.
Ein Kunde möchte ein Programm, das jenes gewisse, von mir gelegentlich erwähnte Dateiformat nach bestimmten Vorgaben nach XML konvertiert.
Da es dafür keine allgemeingültige Dokumenttypdefinition gibt, habe ich die selbst entwickelt.
So weit, so gut.
Eigentlich war ich mit der Programmentwicklung schon weit vorangeschritten. Jetzt hat sich jedoch ein Fehler offenbart.
In weiser Voraussicht hatte ich die vorkommenden Zeichenketten in einen CDATA-Block eingekapselt, in der Annahme, dass dort auch einzelne Nicht-ASCII-Zeichen zulässig sind (zumindest wenn man UTF-8 als Encoding wählt).
Tja .. und jetzt hat es bei einer vom Kunden zur Verfügung gestellten Testdatei den XML-Parser, der die Gültigkeit des Dokumentes überprüfen sollte, rausgehaut.
Also habe ich nachgesehen, wo das Problem liegt, und siehe da: Da ist ein Nicht-ASCII-Zeichen in einem String, wo es eigentlich gar nicht sein dürfte.
Die Ursache liegt also in einer von vornherein nicht-validen Testdatei.
Das kommt gar nicht so selten vor, dass existierende Dateien eigentlich nicht konform zur Standardspezifikation sind. Die Hersteller schludern da alle mehr oder weniger.
Aber was soll ich machen? Ich darf den Inhalt ja nicht einfach verändern.
Als – vorübergehenden – Workaround ersetze ich jetzt alle entsprechenden Nicht-ASCII-Zeichen (also n > 127) in Textstrings durch eine äquivalente Entity der Form „&#n;“.
Das ist zwar keine Lösung, aber wenigstens komme ich erst mal weiter, und kann mir später noch Gedanken darüber machen, wie ich damit verfahre.
Nachtrag:
Mit dem folgenden Inhalt einer XML-Datei lässt sich das Problem reproduzieren:
<?xml version=“1.0″ encoding=“UTF-8″?>
<!– Test (C) breakpoint –>
<ABC>
<DEF>
<GHI>OK</GHI>
<JKL>Funktioniert</JKL>
<GHI><![CDATA[Geht]]></GHI>
<GHI><![CDATA[Geht nicht: º]]></GHI>
</DEF>
</ABC>
<!– Test © breakpoint –>
Kopieren, in Texteditor pasten, mit XML-Extension abspeichern.
Beispiel für Fehlermeldung:
XML-Verarbeitungsfehler: nicht wohlgeformt
Adresse: file://///cn/z/Test.xml
Zeile Nr. 8, Spalte 28:
<GHI><![CDATA[Geht nicht: �]]></GHI> ----------------------------------^
Oder
An invalid character was found in text content. Error processing resource 'file://///cn/z/Test.xml'. Line 8, Position 28
(das nächste Mal mach‘ ich Screenshots ..)
Das ist doch eine „Momentaufnahme“ oder.
Auf z.B http://coderanch.com würde Dir bestimmt geholfen
LikeLike
Ja, schon. Das ist der aktuelle Stand von gestern nachmittag (bis wir wider mal zu einem Geschäftsessen aufbrechen mussten).
LikeLike
Was ist denn das »gewisse« Dateiformat? Kann es sein, dass dort etwas nicht standardgerecht ist?
LikeLike
Wenn ich das Dateiformat nennen würde, wäre es aus mit meiner Annenühmität.
Ja, die Testdatei ist nicht standardgerecht, aber das ist fast schon normal. Viele solche Dateien haben irgendwelche Macken. Deshalb programmiere ich sehr fehlertolerant.
LikeLike
UTF8 heißt nicht, das man da in den Datenstrom einfach jedes beliebige Bitmuster reinknallen kann; so ist z.B. der Bereich 0x80 bis 0xBF nur zulässig, wenn zuvor ein Sequenzstart (obere beide Bits gesetzt / 0xC0-0xFF) kam. Man muß schon alle non-ASCII-Zeichen auch tatsächlich als UTF8 eincodieren.
Das ungültige Zeichen im Beispiel ist 0xBA und ist damit ungültiges UTF8, weil zuvor kein Sequenzstart, sondern ein Whitespace (0x20) war. Richtig muß es als 0xC2 0xBA serialisiert werden, eben halt standardmäßiges UTF8.
LikeLike
Vielen Dank für den Hinweis.
Das werde ich ASAP ausprobieren.
LikeLike
Aber warum ist das ein Problem für den XML-Parser? Wie gesagt, CDATA sollte eigentlich nicht durch den Parser gehen (und tut es laut w3c auch nicht).
LikeLike
Das wüsste ich auch gerne.
Immerhin funktioniert jetzt z.B. 0xBA, wenn ich mit 0xC2 escape.
Umlaute und ß machen nach wie vor Schwierigkeiten.
LikeLike
@minph: Korrekt, das CDATA wird nicht geparsed, aber der Inhalt muß trotzdem der vorgegebenen Codierung entsprechen.
@anne: Umlaute in der ISO-Codepage sind im Bereich 0xC0-0xFF. Da wäre der Sequenzanfang 0xC3 (11 0 00011b, die oberen drei bit kennzeichnen die Sequenz als 2 Byte lang, die unteren 5 bit ergeben im codierten Zeichen Bits 6-10) und dann im folgende Byte die unteren 6 bit des codierten Zeichens, und Bit 7 gesetzt. Bei 0xDF (ß) wäre das also 0xC3 0x9F.
Kurz als vereinfachtes C-Code-Beispiel:
void outputUTF8(unsigned char c)
{
if(c>6));
putByte((c&0x3F)|0x80);
}
}
LikeLike
Du hast mir sehr geholfen, dankeschön.
Dein Hinweis, dass ich escapen muss, hat mich auf die richtige Spur gebracht, und ich nutze jetzt eine Funktion, die meine ANSI-Strings korrekt nach UTF8 konvertiert.
Man lernt doch nie aus!
LikeLike
Argh, der Editor hat die geschweiften Klammern versemmelt, also nochmal in Pseudo-Schreibweise:
void outputUTF8(unsigned char c)
begin
if(c>6));
putByte((c&0x3F)|0x80);
end
LikeLike
Noch’n Versuch (escaped WP etwa keine spitzen Klammern im Text?!)
void outputUTF8(unsigned char c)
begin
if(c<0x80)
putByte(c);
end else begin
putByte(0xC0 or (c>>6));
putByte((c and 0x3F) or 0x80);
en
LikeLike
Schon OK!
Tja, das Escapen immer .. 😈
LikeLike
Eieiei, was soll ich denn dazu kommentieren?
If
irgendwo ein Fehler then
do it richtig
or
forget it
End if
😉
LikeGefällt 1 Person
Ach, Molly .. damit verdiene ich meinen Lebensunterhalt. Nix mit „forget it“.
LikeLike
Gutes Argument. ^^
LikeLike
???; mhhm, tja, interessant, also wenn man das so sieht ist das ja logisch…
Kommt mir vor wie die Antwort meiner Software-Kollegen auf gelegentliche Fragen von mir, ob dadurch der Kunde irgendein Nachteil bekommt. aber diese Fragen verstehen meine Kollegen wiederum nicht.
Also mache ich dann das Planspiel „Jezek mimt den dummen, zahlenden Kunden“: Wenn ich die Kiste jetzt einschalte, was passiert dann? Fahrt das Betriebssystem störungsfrei ´hoch? Ebenso die Anwendung? Kann ich das PW eingeben? usw. usw.
LikeLike
Trotz aller Planung kommt es immer wieder mal zu unvorhergesehenen Problemen.
Auch mit umfangreicher Erfahrung ist man da nie sicher.
Dann ist es gut, wenn man das Problem relativ kurzfristig wieder lösen kann.
LikeLike
Es war schön immer so, dass das Abfangen von Fehlern komplexer als die eigentliche Funktion ist.
LikeGefällt 1 Person
Du sprichst ein wahres Wort!
LikeGefällt 1 Person
Pingback: Ein Tweet kommt selten allein – #SpeakFreely //1569 | breakpoint