3 - Leerzeichen und andere Entitäten / BLANKS and other entities
Der Begriff der Entität ist den meisten vermutlich durch das Entity Relationship Model (ERM) geläufig. Es stellt die Grundlage für das Entwerfen von Datenbanken und Tabellen dar und für VFP Entwickler sollte das nun wirklich kein Böhmisches Dorf sein. Als datengetriebene Entwicklungsumgebung ist dies schließlich unser tägliches Brot.
In HTML versteht man unter Entitäten jedoch etwas ganz anderes. Sie ermöglichen es bestimmte Zeichen auf eine andere Art darzustellen.
Eine einfache Suche nach "Representational State Transfer" sieht bspw. so aus:
https://www.google.com/search
?client=firefox-b
&source=hp
&ei=POOxW6TEONLQrgSN2LTQDA
&q=Representational+State+Transfer
&oq=Representational+State+Transfer
&gs_l=psy-ab.3..0l3j0...
Quelle:Google®Dies entspricht dem grundsätzlichen Aufbau einer URI.
https://max:muster@www.example.com:8080/index.html?p1=A&p2=B#ressource
\___/ \_/ \____/ \_____________/ \__/\_________/ \_______/ \_______/
| | | | | | | |
Schema | Kennwort Host Port Pfad Query Fragment
Benutzer
Quelle: https://de.wikipedia.org/wiki/URL-EncodingEine URI ohne Leerzeichen und mit einer festen Struktur zur Parameterübergabe.
Der erste Parameter bzw. der Beginn des Parameterblocks wird mit einem einfachen Fragezeichen eingeleitet dem ein Name=Wert Paar folgt. Alle anschließenden Parameterpaare werden mit einem kaufmännischen UND/et (&) angehängt. Die Suchmaschine würde allerdings ein ernstes Problem bekommen, wenn nun im Suchbegriff ebenfalls eines dieser beiden Zeichen enthälten wäre. Eine fehlerhafte URI wäre das Resultat.
Da die zu übermittelnden Daten über HTTP(S) transportiert werden, müssen wir berücksichtigen, dass es in HTML reservierte Zeichen und Symbole gibt, die wir klartextlich nicht übergeben dürfen. Entweder weil sie nicht ohne weiteres dargestellt werden können oder weil sie für besondere Aufgaben und Kennzeichnungen reserviert sind.
Die betreffenden Zeichen müssen zuvor in HTML verständliche Entitäten gewandelt werden. Berechtigterweise kann nun angeführt werden, dass beim http Request über die Methode setRequestHeader() ein passender Zeichensatz definiert werden kann, so dass uns eine Konvertierung erspart bleibt. Bei den von mir angesprochenen Webservices kam es jedoch trotzdem zu Zeichensatzproblemen so dass ich die folgende Zeile anschließend wieder auskommentiert habe:
oXmlHttp.setRequestHeader( [Content-Type], [text/xml;charset=Windows-1252] )
Bei URIs müssen wir eine Unterscheidung zwischen der %-basierenden und der &-basierenden Codierung treffen. Bei einfachen Name=Wert Paaren ist eine %-Codierung notwendig. Diese Codierungen sind hexadezimal. Das Leerzeichen (ASC 32) wird beispielsweise durch HEX 20 (%20) ersetzt.
Der folgende als Übergabewert zusammengestellte Parameterstring
?name=abc def&strasse=Testgasse 12
erzeugt eine ungültige URI. Mit einer %-Codierung sähe die Parameterübergabe so aus:
?name=abc%20def&strasse=Testgasse%2012
Übergeben wir jedoch als Wert einen JSON String, dann ist eine Umsetzung von speziellen Zeichen innerhalb des Strings auf Basis von "&;" meist erfolgreicher.
Eine umfangreiche Liste der XML und HTML Entitäten findet sich auf:
https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
Hier nun ein wenig Mustercode für ein Konvertierungsprogramm in dem nicht erlaubte Zeichen in eine URI konforme Kodierung (HTML entities) transformiert werden:
FUNCTION URIConverter as String * // see link above for a complete list LPARAMETERS vStream as String * // has to run first!!!! m.vStream = STRTRAN( m.vStream , CHR( 38 ) , [&] ) && & * // now the rest... m.vStream = STRTRAN( m.vStream , CHR( 9 ) , [ ] )
&& TAB m.vStream = STRTRAN( m.vStream , [<] , [<] ) && < m.vStream = STRTRAN( m.vStream , [>] , [>] ) && > m.vStream = STRTRAN( m.vStream , CHR( 10 ) , [<br/>] ) && LF m.vStream = STRTRAN( m.vStream , CHR( 13 ) , [] ) && CR m.vStream = STRTRAN( m.vStream , ["] , ["] )
&& " m.vStream = STRTRAN( m.vStream , [ä] , [ä] )
&& ä m.vStream = STRTRAN( m.vStream , [Ä] , [Ä] )
&& Ä m.vStream = STRTRAN( m.vStream , [ö] , [ö] )
&& ö m.vStream = STRTRAN( m.vStream , [Ö] , [Ö] )
&& Ö m.vStream = STRTRAN( m.vStream , [ü] , [ü] )
&& ü m.vStream = STRTRAN( m.vStream , [Ü] , [Ü] )
&& Ü m.vStream = STRTRAN( m.vStream , [ß] , [ß] )
&& ß m.vStream = STRTRAN( m.vStream , [à] , [à] )
&& à m.vStream = STRTRAN( m.vStream , [á] , [á] ) && á m.vStream = STRTRAN( m.vStream , [â] , [â] ) && â m.vStream = STRTRAN( m.vStream , [À] , [À] ) && À m.vStream = STRTRAN( m.vStream , [Á] , [Á] ) && Á m.vStream = STRTRAN( m.vStream , [Â] , [Â] ) && Â m.vStream = STRTRAN( m.vStream , [è] , [è] ) && è m.vStream = STRTRAN( m.vStream , [é] , [é] ) && é m.vStream = STRTRAN( m.vStream , [ê] , [ê] ) && ê m.vStream = STRTRAN( m.vStream , [È] , [È] ) && È m.vStream = STRTRAN( m.vStream , [É] , [É] ) && É m.vStream = STRTRAN( m.vStream , [Ê] , [Ê] ) && Ê m.vStream = STRTRAN( m.vStream , [ì] , [ì] ) && ì m.vStream = STRTRAN( m.vStream , [í] , [í] ) && í m.vStream = STRTRAN( m.vStream , [î] , [î] ) && î m.vStream = STRTRAN( m.vStream , [Ì] , [Ì] ) && Ì m.vStream = STRTRAN( m.vStream , [Í] , [Í] ) && Í m.vStream = STRTRAN( m.vStream , [Î] , [Î] ) && Î m.vStream = STRTRAN( m.vStream , [ò] , [ò] ) && à m.vStream = STRTRAN( m.vStream , [ó] , [ó] ) && á m.vStream = STRTRAN( m.vStream , [ô] , [ô] ) && â m.vStream = STRTRAN( m.vStream , [Ò] , [Ò] ) && À m.vStream = STRTRAN( m.vStream , [Ó] , [Ó] ) && Á m.vStream = STRTRAN( m.vStream , [Ô] , [Ô] ) && Â m.vStream = STRTRAN( m.vStream , [ù] , [ù] ) && ù m.vStream = STRTRAN( m.vStream , [ú] , [ú] ) && ú m.vStream = STRTRAN( m.vStream , [û] , [û] ) && û m.vStream = STRTRAN( m.vStream , [Ù] , [Ù] ) && Ù m.vStream = STRTRAN( m.vStream , [Ú] , [Ú] ) && Ú m.vStream = STRTRAN( m.vStream , [Û] , [Û] ) && Û m.vStream = STRTRAN( m.vStream , [ç] , [ç] ) && ç m.vStream = STRTRAN( m.vStream , [Ç] , [Ç] ) && Ç RETURN m.vStream ENDFUNC
Die Liste der als Entität darstellbaren Symbole und Sonderzeichen würde den Code um einiges vergrößern. Das habe ich mir im obigen Beispiel gespart und kann nach Bedarf relativ einfach ergänzt werden. Die notwendigen Informationen stehen über den darüber stehenden Link auf Abruf zur Verfügung.
Je nach Aufbau der URI sollten sowohl einzelne Parameterwerte als auch im Vorfeld generierte JSON Streams über solch einen Konverter laufen. Am Beispiel eines kompletten Objektes sieht es wie folgt aus:
TEXT TO lcJSONData TEXTMERGE NOSHOW PRETEXT 2+4+8
"int1" : <<myCursor.Column1>>,
"int2" : <<myCursor.Column2>>,
"text1" : "<<ALLTRIM( myCursor.Column3 )>>",
"int3" : <<myCursor.Column4>>,
"text2" : "<<ALLTRIM( myCursor.Column5 )>>"
ENDTEXT
lcJSONData = [{] + URIConverter( lcJSONData ) + [}]
Wollen wir jedoch auf Nummer sicher gehen, dann macht es durchaus Sinn, nicht erst den komplett generierten Datenblock zu konvertieren. Wollen wir die Korrektur für jedes Textfeld individuell durchführen, dann sieht der Code folgendermaßen aus:
TEXT TO lcJSONData TEXTMERGE NOSHOW PRETEXT 2+4+8
"int1" : <<myCursor.Column1>>,
"int2" : <<myCursor.Column2>>,
"text1" : "<<URIConverter( ALLTRIM( myCursor.Column3 ) )>>",
"int3" : <<myCursor.Column4>>,
"text2" : "<<URIConverter( ALLTRIM( myCursor.Column5 ) )>>"
ENDTEXT
lcJSONData = [{] + lcJSONData + [}]
Wie bereits erwähnt sind einzelne URI-Parameterwerte bei einem %-Konverter besser aufgehoben. Dies bedeutet, dass wir vor dem konkatenieren eines Name=Wert Paares den Wert über einen %-Konverter jagen der sowohl eine eigene Funktion als auch im bereits gesehenen Konverter als 2. Parameter aktiviert werden kann.
Im folgenden Codemuster wird der URIConverter() um einen entsprechenden Parameter ergänzt.
FUNCTION URIConverter as String
LPARAMETERS vStream as String, vVariante as String
m.vVariante = EVL( m.vVariante , [&] )
DO CASE
CASE m.vVariante = [&]
* // has to run first!!!!
m.vStream = STRTRAN( m.vStream , CHR( 38 ) , [&] ) && &
* // now the rest...
m.vStream = STRTRAN( m.vStream , CHR( 9 ) , [ ] ) && TAB
m.vStream = STRTRAN( m.vStream , [<] , [<] ) && <
m.vStream = STRTRAN( m.vStream , [>] , [>] ) && >
m.vStream = STRTRAN( m.vStream , CHR( 10 ) , [<br/>] ) && LF
m.vStream = STRTRAN( m.vStream , CHR( 13 ) , [] ) && CR
m.vStream = STRTRAN( m.vStream , [ ] , [ ] ) && SPACE
m.vStream = STRTRAN( m.vStream , ["] , ["] ) && "
m.vStream = STRTRAN( m.vStream , [ä] , [ä] ) && ä
m.vStream = STRTRAN( m.vStream , [Ä] , [Ä] ) && Ä
m.vStream = STRTRAN( m.vStream , [ö] , [ö] ) && ö
m.vStream = STRTRAN( m.vStream , [Ö] , [Ö] ) && Ö
m.vStream = STRTRAN( m.vStream , [ü] , [ü] ) && ü
m.vStream = STRTRAN( m.vStream , [Ü] , [Ü] ) && Ü
m.vStream = STRTRAN( m.vStream , [ß] , [ß] ) && ß
m.vStream = STRTRAN( m.vStream , [à] , [à] ) && à
m.vStream = STRTRAN( m.vStream , [á] , [á] ) && á
m.vStream = STRTRAN( m.vStream , [â] , [â] ) && â
m.vStream = STRTRAN( m.vStream , [À] , [À] ) && À
m.vStream = STRTRAN( m.vStream , [Á] , [Á] ) && Á
m.vStream = STRTRAN( m.vStream , [Â] , [Â] ) && Â
m.vStream = STRTRAN( m.vStream , [è] , [è] ) && è
m.vStream = STRTRAN( m.vStream , [é] , [é] ) && é
m.vStream = STRTRAN( m.vStream , [ê] , [ê] ) && ê
m.vStream = STRTRAN( m.vStream , [È] , [È] ) && È
m.vStream = STRTRAN( m.vStream , [É] , [É] ) && É
m.vStream = STRTRAN( m.vStream , [Ê] , [Ê] ) && Ê
m.vStream = STRTRAN( m.vStream , [ì] , [ì] ) && ì
m.vStream = STRTRAN( m.vStream , [í] , [í] ) && í
m.vStream = STRTRAN( m.vStream , [î] , [î] ) && î
m.vStream = STRTRAN( m.vStream , [Ì] , [Ì] ) && Ì
m.vStream = STRTRAN( m.vStream , [Í] , [Í] ) && Í
m.vStream = STRTRAN( m.vStream , [Î] , [Î] ) && Î
m.vStream = STRTRAN( m.vStream , [ò] , [ò] ) && à
m.vStream = STRTRAN( m.vStream , [ó] , [ó] ) && á
m.vStream = STRTRAN( m.vStream , [ô] , [ô] ) && â
m.vStream = STRTRAN( m.vStream , [Ò] , [Ò] ) && À
m.vStream = STRTRAN( m.vStream , [Ó] , [Ó] ) && Á
m.vStream = STRTRAN( m.vStream , [Ô] , [Ô] ) && Â
m.vStream = STRTRAN( m.vStream , [ù] , [ù] ) && ù
m.vStream = STRTRAN( m.vStream , [ú] , [ú] ) && ú
m.vStream = STRTRAN( m.vStream , [û] , [û] ) && û
m.vStream = STRTRAN( m.vStream , [Ù] , [Ù] ) && Ù
m.vStream = STRTRAN( m.vStream , [Ú] , [Ú] ) && Ú
m.vStream = STRTRAN( m.vStream , [Û] , [Û] ) && Û
m.vStream = STRTRAN( m.vStream , [ç] , [ç] ) && ç
m.vStream = STRTRAN( m.vStream , [Ç] , [Ç] ) && Ç
CASE m.vVariante = [%]
LOCAL lcReserved as String, liLoop as Integer, ;
lcOrgChar as String, lcHexCode as String
* // defining chars for converting to entities
lcReserved = [%?&!"#$'()*+,-./:;<=>@\{|}§] ;
+ '[ ]' + CHR( 10 ) + CHR( 13 ) ;
+ [ßäöüÄÖÜàáâÀÁÂèéêÈÉÊìíîÌÍÎòóôÒÓÔùúûÙÚÛçÇ]
* // loop through definition string
FOR liLoop = 1 TO LEN( lcReserved )
* // extract char to convert
lcOrgChar = SUBSTR( lcReserved , liLoop , 1 )
* // convert char to URI Hexcode entity
lcHexCode = [%] + RIGHT( TRANSFORM( ASC( lcOrgChar ) , [@0x] ) , 2 )
m.vStream = STRTRAN( m.vStream , lcOrgChar , lcHexCode )
ENDFOR
ENDCASE
RETURN m.vStream
ENDFUNC
Als nächster Schritt steht nun das Umwandeln unserer auf einem Cursor basierenden Daten in einen JSON String auf der Liste der Vorarbeiten. Dazu dann mehr im nächsten Teil.
Links zu den restlichen Kapiteln:
Einführung / Introduction
Teil 1: Abkürzungen und was sie bedeuten/ Abbreviations and their meaning
Teil 2: Wer ReST sagt, sagt auch JSON
/ In for a ReST, in for a JSON
Teil 3: Leerzeichen und andere Entitäten
/ BLANKS and other entities
Teil 4: JSON und der goldene Konverter
/ JSON and the golden converter
Teil 5: Die Startvorbereitungen
/ preparations for launch
Teil 6: Kleine Denkpause gefällig?
/ in need of a reflection period?
Teil 7: Fertig machen zur Landung
/ preparing for landing
Keine Kommentare:
Kommentar veröffentlichen