XPath 3.0, XPath 2.0, XPath 1.0 / XPath-Funktionen / Stringfunktionen / XPath: Codepoints

XPath: Codepoints

XPath: Codepoints

➪ Die Spezialfunktionen string-to-codepoints, codepoints-to-string und codepoint-equal unterstützen die Konvertierung von Strings in Codepoints sowie den Vergleich von Zeichenketten auf Codepoint-Basis.

Bekanntlich ist jedem Zeichen ein eindeutiger Codepoint zugewiesen. Hier einige wenige Beispiele:

0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
H H
u u
g g
o o

Siehe hierzu meine Anmerkungen zum Thema Encoding.

string-to-codepoints

Die Funktion string-to-codepoints konvertiert einen String in seine Codepoints. Das XPath-Statement //Ort[1]/Mensch[1]/vorname beinhaltet den Textwert "Hugo", und die Funktion string-to-codepoints generiert daraus "72 117 103 111".


<xsl:value-of 
     select="string-to-codepoints(//Ort[1]/Mensch[1]/vorname)"/>

Wichtig ist dabei, dass das XPath-Statement maximal ein einziges Item anspricht (vgl. die Funktionen , und ). Ein //Mensch/vorname findet jedoch möglicherweise eine ganze Nodeliste, was die beliebte Fehlermeldung "A sequence of more than one item is not allowed ... " zur Folge hat.


<xsl:value-of 
     select="string-to-codepoints(//Mensch/vorname)"/>

Fehlermeldung:


Fehlerlevel: fatal
Beschreibung: XPTY0004: A sequence of more than one item is not allowed 
as the first argument of string-to-codepoints() ("Hugo", "Helmut", ...)
Anfang: 16:0
URL: http://www.w3.org/TR/xpath20/#ERRXPTY0004

codepoints-to-string

Umgekehrt transformiert der Aufruf codepoints-to-string((72, 117, 103, 111)) (jawohl, doppelte runde Klammern!) eine Codepoint-Liste wieder in einen String.


<xsl:value-of 
     select="codepoints-to-string((72, 117, 103, 111))"/>

codepoint-equal

Die Funktion codepoint-equal vergleicht zwei Strings auf der Codepoint-Ebene, entsprechend der "Unicode-code point collation" (http://www.w3.org/2005/02/xpath-functions/collation/codepoint):


<xsl:variable 
     name="v1" 
     select="string(//Ort[1]/Mensch[1]/vorname)"/>
<xsl:variable 
     name="v2" 
     select="string(//Ort[1]/Mensch[2]/vorname)"/>
<xsl:value-of 
     select="codepoint-equal($v1, $v2)"/>

codepoint-equal eignet sich nicht dazu, wie Sie vielleicht denken mögen, zwei Codepoint-Listen als Parameter zu übergeben und diese vergleichen zu lassen.


<xsl:variable name="v1" 
  select="string-to-codepoints(//Ort[1]/Mensch[1]/vorname)"/>
<xsl:variable name="v2" 
  select="string-to-codepoints(//Ort[1]/Mensch[2]/vorname)"/>
<xsl:value-of select="codepoint-equal($v1, $v2)"/>

Die Fehlermeldung lautet im Detail:


Fehlerlevel: fatal
Beschreibung: XPTY0004: A sequence of more than one item 
is not allowed as the first argument of codepoint-equal() (72, 117, ...)
Anfang: 15:0
URL: http://www.w3.org/TR/xpath20/#ERRXPTY0004

Auch der Ansatz, die Codepoints in folgender Form zu übergeben, schlägt fehl:


<xsl:value-of 
     select="codepoint-equal(
                  (72, 117, 103, 111), 
                  (72, 101, 108, 109, 117, 116))"/>

Die Fehlermeldung lautet im Detail:


Fehlerlevel: fatal
Beschreibung: XPTY0004: Required item type of first argument of 
codepoint-equal() is xs:string; supplied value has item type xs:integer
URL: http://www.w3.org/TR/xpath20/#ERRXPTY0004

Spezialsuche

Hin und wieder besteht die Notwendigkeit, in einer ganzen Anzahl diverser Dateien nach einem speziellen Codezeichen zu suchen, das zu allem Überfluss auch nicht darstellbar ist. Irgendein Programm meckert beispielsweise, es könne den Codepoint 150 beim besten Willen nicht ausstehen. Und irgendwo in den relevanten Dateien steckt dieses Zeichen. Aber wo?

Eine sehr angenehme Möglichkeit, die XSLT 2.0 zu bieten hat, ist der gleichzeitige Zugriff auf zahlreiche XML-Dokumente mittels der -Funktion. Über base-uri() bekommen Sie auch den jeweiligen Dateinamen heraus.

Die folgende Logik löst das Problem, dass sich in einer dieser XML-Dateien ein nicht druckbares Unicode-Zeichen 150 eingeschlichen hat, das Probleme in der Weiterverarbeitung bereitet und deswegen gefunden werden muss.


<xsl:for-each 
     select="collection(
             'file:///c:/path-to-files?select=*.xml;recurse=yes')">
  <xsl:variable 
       name="vfilename" 
       select="base-uri()"/>
  <erg filename="{$vfilename}">
  <xsl:for-each 
       select="/descendant-or-self::*
               [contains(., codepoints-to-string(150))]">    
    <ja wert="{codepoints-to-string(150)}" inhalt="{.}">
    <xsl:value-of select="string-to-codepoints(.)"/>
    </ja>
  </xsl:for-each>
  </erg>
</xsl:for-each>

Etwas einfacher ist die Sache, wenn die Datei mit dem Problem bereits bekannt ist:


 <xsl:template match="/">
  <xsl:variable name="vsvgfile" 
                select="fn:doc('C:/wg/SVG.xml')"/>
  <erg>
   <xsl:for-each 
        select="$vsvgfile/descendant-or-self::*
                  [contains(., 
                            codepoints-to-string(150))]">
    <absatz>
     <xsl:for-each select="string-to-codepoints(.)">
      <bbb zeichen="{codepoints-to-string(.)}">
       <xsl:value-of select="."/>
      </bbb>
     </xsl:for-each>
    </absatz>
   </xsl:for-each>
  </erg>
 </xsl:template>

Möglich ist auch, das gesuchte Zeichen durch ein lesbares Zeichen zu ersetzen, das dann in der Ausgabe leichter gefunden werden kann.


<xsl:value-of 
     select="replace(., codepoints-to-string(150), 'Y')"/>

wg / 5. April 2018



Fragen? Anmerkungen? Tips?

Bitte nehmen Sie Kontakt zu mir auf.






Vielen Dank für Ihr Interesse an meiner Arbeit.


V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de

www.wilfried-grupe.de/codepoints-to-string.html