C#.NET * C++ * JAVASCRIPT * PYTHON * XML
* XML-SCHEMA * XPATH * XSL * XSL-FO * SVG * XQUERY * XPROC



XPath / 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.

Auf dieser Seite:

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')"/>

Alternative Lösung in XPath 3.0 / XQuery

über , und :


//Ort/Mensch/vorname => for-each( function($p) {
  <wert inhalt="{$p}">{
               string-to-codepoints($p)
               } </wert> } )

Ergebnis:


<wert inhalt="Hugo">72 117 103 111</wert>
<wert inhalt="Nicole">78 105 99 111 108 101</wert>
<wert inhalt="Stefan">83 116 101 102 97 110</wert>
<wert inhalt="Stefan">83 116 101 102 97 110</wert>
<wert inhalt="Siggi">83 105 103 103 105</wert>
<wert inhalt="Heini">72 101 105 110 105</wert>
<wert inhalt="Rudi">82 117 100 105</wert>
<wert inhalt="Karl">75 97 114 108</wert>
<wert inhalt="Simone">83 105 109 111 110 101</wert>
<wert inhalt="Horst">72 111 114 115 116</wert>
<wert inhalt="Werner">87 101 114 110 101 114</wert>
<wert inhalt="Ludwig">76 117 100 119 105 103</wert>
<wert inhalt="Willi">87 105 108 108 105</wert>
<wert inhalt="Rita">82 105 116 97</wert>
<wert inhalt="Susi">83 117 115 105</wert>
<wert inhalt="Lotte">76 111 116 116 101</wert>
<wert inhalt="Betty">66 101 116 116 121</wert>
<wert inhalt="Martin">77 97 114 116 105 110</wert>
<wert inhalt="Liane">76 105 97 110 101</wert>

Ein anderes Beispiel:


(40 to 60) => for-each( function($p) {
  <wert inhalt="{$p}">{
                codepoints-to-string($p)
               } </wert> } )

Ergebnis:


<wert inhalt="40">(</wert>
<wert inhalt="41">)</wert>
<wert inhalt="42">*</wert>
<wert inhalt="43">+</wert>
<wert inhalt="44">,</wert>
<wert inhalt="45">-</wert>
<wert inhalt="46">.</wert>
<wert inhalt="47">/</wert>
<wert inhalt="48">0</wert>
<wert inhalt="49">1</wert>
<wert inhalt="50">2</wert>
<wert inhalt="51">3</wert>
<wert inhalt="52">4</wert>
<wert inhalt="53">5</wert>
<wert inhalt="54">6</wert>
<wert inhalt="55">7</wert>
<wert inhalt="56">8</wert>
<wert inhalt="57">9</wert>
<wert inhalt="58">:</wert>
<wert inhalt="59">;</wert>
<wert inhalt="60">&lt;</wert>

wg / 22. März 2020



Fragen? Anmerkungen? Tipps?

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