View Full Version : DB2 / SQL / String auf gültige Zeichen prüfen
Hallo Forum,
ich habe folgendes Problem:
ich lese aus einer DB2-Tabelle Daten, die in XML umgesetzt werden. Dafür erzeuge ich mit Hilfe von SQL eine Zwischendatei. Ein Tag sieht so aus:
Exec Sql
Insert into temp
(XMLSTRING)
values(
XMLSERIALIZE(
XMLDOCUMENT(
XMLELEMENT(NAME "ingredients", trim(Char(:variable)))
)
AS VARCHAR(5000) CCSID 1208
));
Enthält "variable" ungültige Zeichen, fällt mein SQL mit einem SQLCOD von -20377 auf die Nase.
Wie schaffe ich es, ungültige Zeichen vor dem SQL herauszufiltern? Oder gibt es eine SQL-Funktion, die ich nur nicht finden kann? ;-)
Fehlerbeschreibung hier:
https://www.ibm.com/support/knowledgecenter/SSEPEK_10.0.0/com.ibm.db2z10.doc.codes/src/tpc/n20377.dita
Da steht euch eine Liste der gültigen Zeichen.
Gruß,
Frederik
Die Frage ist, was sind ungültige Zeichen?
In einem Element (Attribut oder Knoten) darf z.B. natürlich kein "<" vorkommen, da damit wieder XML eingeleitet wird.
Hierfür benötigst du eine SQL-Funktion, die dir die Zeichen übersetzt.
Aus "<" wird dann z.B. "<", aus dem "&" dann "&" usw.
Nicht druckbare Zeichen (Hexwerte) müssen dann in Pseudo-Unicode (ich glaube "#nnnn;" o.ä.) übersetzt werden.
Umgedreht, beim Einlesen benötigst du dann eine Rückübersetzung.
Leider gibt es dafür tatsächlich keine Standard-SQL-Funktion, dafür musst du dir eine schreiben (lassen).
Genaueres kannst du auch hier nachlesen:
https://wiki.selfhtml.org/wiki/Referenz:HTML/Zeichenreferenz
Ungültige Zeichen sind hier Zeichen, die SQL anmeckert (siehe Link oben - da stehen ja im Text die erlaubten Zeichen). Das Problem ist, dass der gesamte Befehl scheitert und mir der Tag in der XML-Datei fehlt.
Ich brauche auch gar nicht den großen Aufwand über Pseudocode; es würde mir reichen, die ungültigen Zeichen mit Spaces zu ersetzen, da ich keine Rückübersetzung brauche. Wie stelle ich das an?
Hintergrund: Hier geht es um Zutatentexte, die von einer Waage aufs Etikett gedruckt werden. Die Daten werden von der AS/400 in XML gewandelt und dann per FTP an die Waage übertragen. Besser als gar keinen Text auszudrucken ist also, die ungültigen Zeichen einfach weg zu lassen.
Wie wärs mit XLATE in RPG ?
Mir ist nicht bekannt, dass XLATE aus 1 Zeichen mehr als 1 Zeichen ersetzt.
Der Vorgang ist da schon etwas komplexer.
Für %XLATE müsste ich aber wissen, WAS ich ersetzen soll. Leider kann in einem einzelnen Zeichen des Strings irgendein Schrott-Hexwert drin stehen. Besser wäre also mit %CHECK oder so zu prüfen, ob die Zeichen gültig sind. Da das aber ne ganze Latte sind (https://www.ibm.com/support/knowledgecenter/SSEPEK_10.0.0/com.ibm.db2z10.doc.codes/src/tpc/n20377.dita) geht das so auch nicht. Ich wüßte auch gar nicht, wie ich da Hex-Werte angebe...
Macht er auch nicht. Muß aber auch nicht, oder? ;)
Ansonsten eben mehrmals %SCAN und %REPLACE oder %SCANRPL (sofern verfügbar).
Mir ist nicht bekannt, dass XLATE aus 1 Zeichen mehr als 1 Zeichen ersetzt.
Der Vorgang ist da schon etwas komplexer.
Siehe obigen Link für die HTML's.
d MySource s 1000 varying
d MyDest s 2000 varying
d Ind s 5i 0
// grobes Beispiel
MyDest = '';
for Ind=1 to %len(MySource);
select;
when %subst(MySource:1:1) < *blank
or %subst(MySource:1:1) >= x'FE';
MyDest += RoutineHexToHtml(%subst(MySource:1:1)); // #xNNNN, N = 0-9A-F
when %subst(MySource:1:1) = '&';
MyDest += '&';
when %subst(MySource:1:1) = '<';
MyDest += '<';
when %subst(MySource:1:1) = '>';
MyDest += '>';
:
:
other;
MyDest += %subst(MySource:1:1);
endsl;
endfor;
Ich bekomms nicht hin. Ich habe es so probiert:
//-----------------------------------------------------------------------
// XML-String prüfen
//-----------------------------------------------------------------------
dcl-proc XMLConvert;
dcl-pi *N;
$string ucs2(5000);
end-pi;
dcl-s #i zoned(4:0);
dcl-s $ch char(1);
dcl-s $temp ucs2(5000);
$temp = '';
for #i = 1 to %len($string);
$ch = %char(%subst($string:#i:1));
if $ch = x'09'
or $ch = x'0A'
or $ch = x'0D'
or ($ch >= x'20' and $ch <= x'D7FF')
or ($ch >= x'E000' and $ch <= x'FFFD')
or ($ch >= x'100000' and $ch <= x'10FFFF');
$temp = $temp + %subst($string:#i:1);
endif;
endfor;
$string = $temp;
return;
end-proc;
Der Ergebnisstring ist aber immer leer. Wenn ich mit Debug durchsteppe, scheint er die Zeile
$temp = $temp + %subst($string:#i:1); gar nicht auszuführen.
Wahrscheinlich sehe ich den Wald aber vor lauter Bäumen nicht mehr. ;-)
Ich geh jetzt mal ins Wochenende und mache am Montag weiter :-)