XML mit Sonderzeichen mittels regexp maskieren
@lex
- perl
Hallo,
versuche mich schon seit einiger Zeit an folgender Problematik. Ich bekomme einen XML-String, der Sonderzeichen im Inhalt enthält. Nun möchte ich bei der Generierung einer XML-Datei per Regexp ungültige Zeichen in den Daten maskieren, um Probleme bspw. mit > oder <-Zeichen zu umgehen.
Bsp:
<person><vorname>Hallo T<homas </vorname></person>
Im Element <vorname> ist ein '<' zuviel und das möchte ich nun bei der Ausgaben als < maskieren. Nun schaff ich es nicht den Inhalt von den Element-Tags zu trennen :(
Hat jemand vielleicht einen Ansatz?
Hiermit probiere ich gerad rum:
my $test = "<person><vorname>V<o?r1</vorname><person>";
$test =~ /(<(.*)>)^<(<(.*)>)/sprintf ("&#%d;", ord ($1))/ge;
print $test;
Besten Dank im Voraus
Alex
Hello out there!
Ich bekomme einen XML-String […]
Bsp:
<person><vorname>Hallo T<homas </vorname></person>
Das ist kein XML (nicht wohlgeformt).
Statt an Symptomen rumdoktern zu wollen, solltest du besser die Ursache bekämpfen, also dafür sorgen, dass das, was XML sein sollte, auch welches ist.
See ya up the road,
Gunnar
Hallo,
es ist schwierig zu beschreiben, aber ich hoffe man kann den Ablauf irgendwie nachvollziehen.
Fakt ist, ist bekomme so den XML-Stream und kann nichts Tiefgreifendes ändern. Kein Sourcecode etc. und noch x Komponenten aus einem gewachsenen System eben. In Perl wird das ganze zusammengesetzt.
Plausibilitätsprüfungen & Co. würd ich gern alles machen, aber momentan ist das leider die einzige Stellschraube :(
Alex
Hello out there!
Fakt ist, ist bekomme so den XML-Stream
Du bekommst also kein XML. Das ist traurig, denn dann kann das, was du da bekommst, nicht als XML verarbeitet werden:
„Wenn ein kritischer Fehler aufgetreten ist, darf ein Prozessor die normale Verarbeitung nicht fortsetzen. […] Verletzungen von Wohlgeformtheitsbeschränkungen sind kritische Fehler.“ [XML §1.2]
Plausibilitätsprüfungen & Co. würd ich gern alles machen, aber momentan ist das leider die einzige Stellschraube :(
„Momentan“ sollte das heißen, was es heißt: dass dieser Missstand von sehr kurzer Dauer ist und demnächst behoben wird.
See ya up the road,
Gunnar
gut, dann formulier ich es anders: es ist die einzige stellschraube!
Ist schön, daß du alles zitieren kannst und weißt wo es auch steht. ist nur keine lösung des problems.
Ist schön, daß du alles zitieren kannst und weißt wo es auch steht. ist nur keine lösung des problems.
Ich habe dir zwei mögliche Lösungswege genannt, wenn du immer noch ein Problem hast, dann aber nicht nur dieses eine.
Siechfred
versuche mich schon seit einiger Zeit an folgender Problematik. Ich bekomme einen XML-String, der Sonderzeichen im Inhalt enthält. Nun möchte ich bei der Generierung einer XML-Datei per Regexp ungültige Zeichen in den Daten maskieren, um Probleme bspw. mit > oder <-Zeichen zu umgehen.
Eventuell genügt eine Behandlung mit HTML::Entities. Ansonsten folge Gunnars Hinweis und mache es XML-gerecht, indem du die Abschnitte als CDATA-Sektion kennzeichnest:
<foo><![CDATA[1 > 0]]></foo>
Siehe: http://de.selfhtml.org/xml/regeln/zeichen.htm#cdata
Siechfred
Hello out there!
Ansonsten folge Gunnars Hinweis und mache es XML-gerecht, indem du die Abschnitte als CDATA-Sektion kennzeichnest:
<foo><![CDATA[1 > 0]]></foo>
Das hatte ich nicht im Sinn, sondern eher:
<foo>1 > 0></foo>
oder <foo>1 > 0></foo>
CDATA-Abschnitte könnten sich bei der Verarbeitung als problematisch erweisen (zusätzlicher Knoten im DOM, ...).
Es dürfte auch einfacher sein, die fünf betroffenen Zeichen (siehe http://de.selfhtml.org/xml/regeln/zeichen.htm#xmleigene) umzuwandeln, Scriptsprachen stellen entsprechende Methoden zur Verfügung.
@@lex:
Wie kommt das "Hallo T<homas " überhaupt in den Quelltext? Nutzereingabe? Diese sollte nicht ungeprüft übernommen und weitergereicht werden, sondern sofort umgewandelt werden – in der Applikation, die die Formulareingaben entgegennimmt. Dann erst kannst du sagen: „Ich bekomme einen XML-String“.
See ya up the road,
Gunnar
Hallo Gunnar.
CDATA-Abschnitte könnten sich bei der Verarbeitung als problematisch erweisen (zusätzlicher Knoten im DOM, ...).
Inwiefern? Ein Textknoten ist auch ein „zusätzlicher Knoten im DOM“.
Einen schönen Montag noch.
Gruß, Mathias
Das hatte ich nicht im Sinn, sondern eher:
Dann drück' dich doch bitte nächstes Mal etwas genauer aus, wenn ich dich nicht richtig verstehe, dann wird es einem Großteil der Leser ähnlich gehen.
Es dürfte auch einfacher sein, die fünf betroffenen Zeichen (siehe http://de.selfhtml.org/xml/regeln/zeichen.htm#xmleigene) umzuwandeln, Scriptsprachen stellen entsprechende Methoden zur Verfügung.
Es geht nicht um einfach oder nicht einfach, es geht um den Anwendungsfall. Bei einer großen Anzahl von Zeichen bzw. bei Inhalten, auf die man keinen Einfluss hat oder die unbehandelt weitergegeben werden sollen, sollte man m.E. - auch aus Performance-Gründen - CDATA-Abschnitte verwenden.
Wie kommt das "Hallo T<homas " überhaupt in den Quelltext? Nutzereingabe? Diese sollte nicht ungeprüft übernommen und weitergereicht werden, sondern sofort umgewandelt werden – in der Applikation, die die Formulareingaben entgegennimmt. Dann erst kannst du sagen: „Ich bekomme einen XML-String“.
Warum? Woher weißt du, was diese "XML-Strings" für Daten beinhalten sollen?
Siechfred
Hello out there!
Das hatte ich nicht im Sinn, sondern eher:
Dann drück' dich doch bitte nächstes Mal etwas genauer aus
Ich hatte mich gar nicht drüber ausgelassen, auf welche Art man aus "<person><vorname>Hallo T<homas </vorname></person>" wohlgeformtes XML machen solle. Ich wollte nur anmerken, dass mir nicht zuerst CDATA, sondern die Maskierung der Zeichen einfiel.
es geht um den Anwendungsfall.
Ja. Tut es das nicht eigentlich auch immer? ;-)
Dann erst kannst du sagen: „Ich bekomme einen XML-String“.
Warum? Woher weißt du, was diese "XML-Strings" für Daten beinhalten sollen?
Ich wollte nur nochmal darauf hinaus, dass "<person><vorname>Hallo T<homas </vorname></person>" gar kein „XML-String“ ist.
See ya up the road,
Gunnar
Das hatte ich nicht im Sinn, sondern eher:
Dann drück' dich doch bitte nächstes Mal etwas genauer aus
Ich hatte mich gar nicht drüber ausgelassen, auf welche Art man aus "<person><vorname>Hallo T<homas </vorname></person>" wohlgeformtes XML machen solle. Ich wollte nur anmerken, dass mir nicht zuerst CDATA, sondern die Maskierung der Zeichen einfiel.
Beides ist ja denkbar. Aber ich wollte eigentlich nur darauf hinaus, dass man Daten entsprechend ihres Inhaltes speichern sollte. Und wenn die unmaskierten Sonderzeichen da einen tieferen Sinn haben (als HTML oder in Programmcode), macht man sich ohne CDATA das Leben nur unnötig schwer, da man die Maskierung vor Weiterverwendung ja erst wieder rückgängig machen müsste. Und längere Strings haben halt den Nachteil, dass man erstmal irgendeine Art von Suchen-und-Ersetzen-Logik drüberjagen muss, was durchaus zu Einbußen bei der Performance führen kann.
Dann erst kannst du sagen: „Ich bekomme einen XML-String“.
Warum? Woher weißt du, was diese "XML-Strings" für Daten beinhalten sollen?
Ich wollte nur nochmal darauf hinaus, dass "<person><vorname>Hallo T<homas </vorname></person>" gar kein „XML-String“ ist.
Haarspalterei ist eigentlich mein Metier! ;)
Siechfred
Moin,
danke Siechfred. Werd ich im Hinterkopf behalten bzgl. CDATA. Ob XML oder nicht, aber wie würde denn der RegExp aussehen, wenn ich bspw.
<vorname>Hallo Thomas </vorname>
"filtern" wollte?
Gruß
aber wie würde denn der RegExp aussehen, wenn ich bspw.
<vorname>Hallo Thomas </vorname>
"filtern" wollte?
Das ist nicht ganz so trivial, da die Sonderzeichen ja nur im String, nicht aber um die Elemente herum maskiert werden sollen. Entweder du wirfst einen XML-Parser an, der dir den Textinhalt liefert, den du dann behandelst, oder du musst einen entsprechenden RegExp bauen. Kleines Beispiel, das du natürlich deinen Bedürfnissen entsprechend ausbauen müsstest:
use strict;
use diagnostics;
use [link:http://search.cpan.org/~gaas/HTML-Parser-3.56/lib/HTML/Entities.pm@title=HTML::Entities];
my $xml = '<foo>"1 > 0"</foo>';
$xml =~ s/(?<=\<foo\>)(.*)(?=\<\/foo\>)/[link:http://search.cpan.org/~gaas/HTML-Parser-3.56/lib/HTML/Entities.pm#encode_entities@title=encode_entities]($1, '<>&"\'')/e;
print $xml;
Das gibt dir aus:
<foo>"1 > 0"</foo>
Wichtig ist der e-Modifier, der dafür sorgt, dass die Funktion encode_entitities bei der Ersetzung ausgeführt wird. Und weil es ja nur um XML geht, kannst du HTML::Entities anweisen, welche Zeichen es ersetzen soll.
Siechfred
Super! Danke.
jetzt sind die Elemente nun auf "foo" festgelegt. Gibt es noch eine Variante die auch x-beliebige Zeilchen akzeptiert?
bei
my $xml = '<foo>"1 > 0"<fooooo>';
$xml =~ s/(?<=\<foo\>)(.*)(?=\<(.*)\>)/encode_entities($1, '<>&"\'')/e;
bekomme ich fast das gewünschte Ergebnis. Wenn ich aber jetzt versuche den ersten Teil <foo> durch beliebige Zeichen (.*) zu "ersetzen", dann kommt leider eine Fehlermeldung :(
Wenn das noch klappen sollte, dann bin sollte es funktionieren wie ich es mir vorstelle :) *hoff*
jetzt sind die Elemente nun auf "foo" festgelegt. Gibt es noch eine Variante die auch x-beliebige Zeilchen akzeptiert?
Ja, auf Umwegen, denn:
Wenn ich aber jetzt versuche den ersten Teil <foo> durch beliebige Zeichen (.*) zu "ersetzen", dann kommt leider eine Fehlermeldung :(
Lookarounds variabler Länge sind nicht möglich. Ich würde folgenden Umweg nehmen:
$xml =~ s/(<([a-z]+)?\>)(.*)(?=\<\/\2\>)/$1.encode_entities($3, '<>&"\'')/e;
Oder gleich mit CDATA arbeiten.
Siechfred
Danke für die Unterstützung.