Joy: EXSLT

Hallo,

ich möchte gerne ein XSLT für ein XML schreiben, welches in den Textknoten des XML Files überprüft, ob Buchstaben und Zahlen verwendet wurden. Wenn keine Buchstaben oder Zahlen enthalten sind (aber Leerzeichen, Zeilenumbrüche oder Tabulatoren), sollen diese Knoten dann gelöscht werden.

Mit einfachen
<xsl:when test="text()[contains(.,a-z) or contains(., 0-9)]"/>
war es nicht möglich.

Brauche ich dafür regular Expressions von EXSLT und wenn ja, wie gehe ich dann weiter vor?

Gruß
Joy

  1. Hallo,

    ich möchte gerne ein XSLT für ein XML schreiben, welches in den Textknoten des XML Files überprüft, ob Buchstaben und Zahlen verwendet wurden. Wenn keine Buchstaben oder Zahlen enthalten sind (aber Leerzeichen, Zeilenumbrüche oder Tabulatoren), sollen diese Knoten dann gelöscht werden.

    Mit einfachen
    <xsl:when test="text()[contains(.,a-z) or contains(., 0-9)]"/>
    war es nicht möglich.

    Brauche ich dafür regular Expressions von EXSLT und wenn ja, wie gehe ich dann weiter vor?

    Nein, du brauchst nicht unbedingt EXSLT. Wenn du XSLT 2.0 verwenden kannst, kannst du mit dem "boardmittel" vom XSLT 2 die aufgabe lösen (auch mit Reg.Exp).

    Kannst du keinen XSLT 2.0 verwenden und willst du die EXSLT-Erweiterungen nützen, ist die erste Frage ob dein XSLT-Prozessor diese unterstützt (darauf gibt die antwort die jeweilige Seite (der gewünschten Funktion) bei exslt.org).
    Ünterstützt dein Prozessor die gewünschte Erweiterung, findest du auf der Seite (bei exslt.org) dazu passende Beispiel XSLTs.

    Ansonsten kannst du es mit einem anderen "Trick" versuchen:
    <xsl:when test="string-length(translate(normalize-space(text()), ' ', '')) = 0"></xsl:when>

    Grüße
    Thomas

    1. Hallo Thomas,

      danke erstmal für deine schnelle Antwort.

      Ich möchte nicht unbedingt EXSLT benutzen sondern es lieber mit den "Tricks" versuchen :-)

      Ansonsten kannst du es mit einem anderen "Trick" versuchen:
      <xsl:when test="string-length(translate(normalize-space(text()), ' ', '')) = 0"></xsl:when>

      Das hat leider nicht funktioniert. In dem XML gibt es Tags bei denen z.Bsp. 1 Zeilenumbruch und 3 Tabulatoren drin sind oder 1 Zeilenumbruch und 4 Tabulatoren u.s.w. Damit ich diese nicht alle per

      <xsl:when test ="text() = '&#10;&#9;&#9;&#9;'"/>

      raussuchen muss wollte ich lieber überprüfen, ob Buchstaben oder Zahlen im Text enthalten sind. Wenn Buchstaben drin sind könnten aber auch Leerzeichen oder Zeilenumbrüche enthalten sein, welche ich nicht ersetzen möchte.

      Z.Bsp:

      <Kapitel>Es war einmal ein Haus blablablabla <br/>
      darin lebten 4 Menschen</Kapitel>
      <Kapitel>
                   </Kapitel>

      XSLT soll nun das zweite Kapitel rauslöschen, da ja kein wirklicher Inhalte drin sind. Leider kann ich das XML nicht vorher schon beeinflussen.

      Gruß
      Joy

      1. Hallo,

        Ansonsten kannst du es mit einem anderen "Trick" versuchen:
        <xsl:when test="string-length(translate(normalize-space(text()), ' ', '')) = 0"></xsl:when>

        Das hat leider nicht funktioniert.

        Das kann ich so einfach nicht glauben (ich habe es mit vier versch. Prozessoren getestet!):

        <xsl:template match="Kapitel">
          xsl:choose
           <xsl:when test="string-length(translate(normalize-space(text()), ' ', '')) = 0"></xsl:when>
           xsl:otherwise
            <xsl:copy-of select="."/>
           </xsl:otherwise>
          </xsl:choose>
         </xsl:template>

        macht genau was es soll, nämlich:

        In dem XML gibt es Tags bei denen z.Bsp. 1 Zeilenumbruch und 3 Tabulatoren drin sind oder 1 Zeilenumbruch und 4 Tabulatoren u.s.w. Damit ich diese nicht alle per

        <xsl:when test ="text() = '&#10;&#9;&#9;&#9;'"/>

        raussuchen muss wollte ich lieber überprüfen, ob Buchstaben oder Zahlen im Text enthalten sind. Wenn Buchstaben drin sind könnten aber auch Leerzeichen oder Zeilenumbrüche enthalten sein, welche ich nicht ersetzen möchte.

        Der Test überprüft indirekt ob andere Zeichen als Leerraumzeichen vorhanden sind.

        normalize-space(text())
        Macht aus den Tabs, Zeilenumbrüchen normale Leerzeichen
        http://de.selfhtml.org/xml/darstellung/xpathfunktionen.htm#normalize_space
        du kannst statt text() auch nur " . "(den aktuellen Knoten) angeben.

        translate(normalize-space(text()), ' ', '') ersetzt dann die Leerzeichen durch 'nichts', so dass wenn es im element keine andere zeichen als Leerraumzeichen waren, jetzt das Element leer ist.
        string-length() zählt die anzal der verbliebenen Zeichen im text(), wenn die jetzt 0 ist, hatte das Element keine andere als Leerraumzeichen drinn.

        Wie gesagt, das funktioniert auch so.
        Wenn es bei dir nicht macht, (welcher XSLT-Prozessor?) sind da eben andere Zeichen als die in XML erlaubten Leerraumzeichen im Element.

        Grüße
        Thomas

        1. Hi Thomas,

          da ist wohl meine zweite Antwort (von 14 Uhr) auf deinen Beitrag etwas hochgerutscht. Es hat funktioniert, ich hatte bei mir nur den falschen Textknoten angegeben. Also vielen Dank nochmal für den "Trick".

          Ich hätte da noch ein zweites Problem, weiß aber nicht ob du dich mal mit DeltaXML beschäftigt hast. Der Service vergleicht zwei XML Files miteinander und zeigt die Unterschiede wieder in einem XML File an. Dabei können verschiedene Filter (In- und OutFitler) mit eingebracht werden.
          Mein Problem liegt beim InFilter. Kennst du DeltaXML?

          Gruß
          Joy

          1. Hallo,

            Ich hätte da noch ein zweites Problem, weiß aber nicht ob du dich mal mit DeltaXML beschäftigt hast. Der Service vergleicht zwei XML Files miteinander und zeigt die Unterschiede wieder in einem XML File an. Dabei können verschiedene Filter (In- und OutFitler) mit eingebracht werden.
            Mein Problem liegt beim InFilter. Kennst du DeltaXML?

            Nein, den Tool kenne ich nicht.
            Meinst du die pre-Filters? http://www.deltaxml.com/dxml/library/guide-to-using-filters.html#dsy98_2-2

            Grüße
            Thomas

            1. Hi Thomas,

              Nein, den Tool kenne ich nicht.
              Meinst du die pre-Filters? http://www.deltaxml.com/dxml/library/guide-to-using-filters.html#dsy98_2-2

              Ja genau die meine ich. Ich möchte gerne vor dem Vergleich falsche Leerzeichen (  bzw. &#xA0;) aus den XML Files rauslöschen und richtige Leerzeichen einsetzen (also ersetzen), damit DeltaXML Wort für Wort vergleicht.
              Die falschen Leerzeichen liest DeltaXML immer als ein Buchstabe und dadurch wird der Text als ein ganzes Wort gelesen. Vielleicht ist aber schon mein Aufruf zum ersetzen der Leerzeichen falsch.

              <xsl:template match="*">
                xsl:copy
                 <xsl:copy-of select="@*" />
                 <xsl:apply-templates />
                </xsl:copy>
               </xsl:template>

              <xsl:template match="xhtml:div">
                xsl:copy
                <xsl:copy-of select="."/>
                xsl:choose
                 <xsl:when test="//text()[contains(.,'Â ')]">
                  <xsl:value-of select="translate(., '&#xA0;', ' ')"/>
                 </xsl:when>
                 xsl:otherwise<!--xsl:apply-templates /--></xsl:otherwise>
                </xsl:choose>
                </xsl:copy>
               </xsl:template>

              Gruß
              Joy

              1. Hallo,

                Nein, den Tool kenne ich nicht.
                Meinst du die pre-Filters? http://www.deltaxml.com/dxml/library/guide-to-using-filters.html#dsy98_2-2

                Ja genau die meine ich. Ich möchte gerne vor dem Vergleich falsche Leerzeichen (  bzw. &#xA0;) aus den XML Files rauslöschen und richtige Leerzeichen einsetzen (also ersetzen), damit DeltaXML Wort für Wort vergleicht.

                Delta empfielt hier schon vorher im Java die Leerzeichen rauszunehmen:
                http://www.deltaxml.com/dxml/library/how-to-manage-white-space/version/live
                Die bieten ja selbst sowohl ein XSLT (normalize-space.xsl) als auch ein JavaClass dazu (com.deltaxml.pipe.filters.NormalizeSpace). Funktionieren die denn nicht?

                Vielleicht ist aber schon mein Aufruf zum ersetzen der Leerzeichen falsch.

                Ja ist er.

                [contains(.,'Â ')]

                Das "Â " ist die Darstellung des UTF-8 Zeichen in ANSI (z.B: ISO-8859-1). Sprich du würdest nur dann ein "Â " in deinem XML haben, wenn das XML durch irgendeinen Vorgang vom UTF-8 zu ANSI "dekodiert" (z.B. einfach im "falschen" Format abgespeichert) worden wäre.
                Jedanfalls, wenn du "Â " und Konserten in deinem XML siehst, ist entweder dein Editor voll daneben (spich keine Unterstützung für UTF8), oder das XML ist unbrauchbar.

                <xsl:template match="xhtml:div">
                  xsl:copy
                  <xsl:copy-of select="."/>
                  xsl:choose
                   <xsl:when test="//text()[contains(.,'Â ')]">

                Du überprüfst den gesamten Text des Dokuments?

                <xsl:value-of select="translate(., '&#xA0;', ' ')"/>
                   </xsl:when>
                   xsl:otherwise<!--xsl:apply-templates /--></xsl:otherwise>
                  </xsl:choose>
                  </xsl:copy>
                </xsl:template>

                Ich verstehe jetzt so nicht ganz, warum du es noch immer auf diese Weise versucht. Es sei denn dein XML ist wirklich unbrauchbar: d.h. du hast in der Tat "Â " da drinn stehen (auch in einem UTF fähigen Editor).
                Dann kannst du das natürlich so ersetzen:
                <xsl:when test=".//text()[contains(.,'Â ')]">
                <xsl:value-of select="translate(.//text(), 'Â', '')"/>

                Aber sonst einfach:
                <xsl:value-of select="normalize-space(.//text())"/>

                Grüße
                Thomas

                1. Hi Thomas,

                  Delta empfielt hier schon vorher im Java die Leerzeichen rauszunehmen:
                  http://www.deltaxml.com/dxml/library/how-to-manage-white-space/version/live
                  Die bieten ja selbst sowohl ein XSLT (normalize-space.xsl) als auch ein JavaClass dazu (com.deltaxml.pipe.filters.NormalizeSpace). Funktionieren die denn nicht?

                  Ich kann sie aber erst mit dem Filter rausnehmen, da ich ohne Java arbeite.

                  Ich verstehe jetzt so nicht ganz, warum du es noch immer auf diese Weise versucht. Es sei denn dein XML ist wirklich unbrauchbar: d.h. du hast in der Tat "Â " da drinn stehen (auch in einem UTF fähigen Editor).

                  Ja, meine XML enthalten diese Zeichen anstelle der Leerzeichen (es gab vorher Formatierungsfehler beim Erstellen der XMLFiles, die nicht manuell behoben werden sollen, deswegen ja der Filter).
                  Überall im Text wo sie auftauchen sollen sie ersetzt werden, aber die restliche Struktur des XML's erhalten bleiben.

                  Dann kannst du das natürlich so ersetzen:
                  <xsl:when test=".//text()[contains(.,'Â ')]">
                  <xsl:value-of select="translate(.//text(), 'Â', '')"/>

                  Ich hab's so probiert:

                  <xsl:template match="*[xhtml:div]">
                    xsl:copy
                     <xsl:if test="//text()[contains(.,'Â ')]">
                      <xsl:value-of select="translate(., '&#xA0;', ' ')"/>
                      </xsl:if>
                    </xsl:copy>
                   </xsl:template>

                  das hat meinen Text zwar bearbeitet aber die restliche Struktur rausgehauen. Und wenn ich ein <xsl:copy-of select="@*" /> mit reinsetze bekomme ich den Text nochmal angezeigt, aber ohne Änderung.

                  Aber sonst einfach:
                  <xsl:value-of select="normalize-space(.//text())"/>

                  Habe ich probiert, hat aber nicht geklappt.

                  Gruß
                  Joy

                  1. Hallo,

                    Ich kann sie aber erst mit dem Filter rausnehmen, da ich ohne Java arbeite.

                    OK.

                    Ich verstehe jetzt so nicht ganz, warum du es noch immer auf diese Weise versucht. Es sei denn dein XML ist wirklich unbrauchbar: d.h. du hast in der Tat "Â " da drinn stehen (auch in einem UTF fähigen Editor).

                    Ja, meine XML enthalten diese Zeichen anstelle der Leerzeichen (es gab vorher Formatierungsfehler beim Erstellen der XMLFiles, [...]).

                    Au weia!

                    Überall im Text wo sie auftauchen sollen sie ersetzt werden, aber die restliche Struktur des XML's erhalten bleiben.

                    Dann kannst du das natürlich so ersetzen:
                    <xsl:when test=".//text()[contains(.,'Â ')]">
                    <xsl:value-of select="translate(.//text(), 'Â', '')"/>

                    Ich hab's so probiert:

                    <xsl:template match="*[xhtml:div]">
                      xsl:copy
                       <xsl:if test="//text()[contains(.,'Â ')]">
                        <xsl:value-of select="translate(., '&#xA0;', ' ')"/>
                        </xsl:if>
                      </xsl:copy>
                    </xsl:template>

                    das hat meinen Text zwar bearbeitet aber die restliche Struktur rausgehauen.

                    Dann gucken wir doch an was es macht:

                    Vorher hattest du: <xsl:template match="xhtml:div">, jetzt hast du
                    <xsl:template match="*[xhtml:div]">
                    sprich: Template für jedes Element das ein xhtml:div als Kind hat. Kein Wunder dass dann die Struktur nicht erhalten bleibt.
                    Dann nimmst du "<xsl:if test="//text() ...">" mit //text() greifst du auf den  gesamten Text im ganzen Dokument . Die is-Abfrage sagt folgendes: "wenn _irgendwo_ im Text des Dokuments ein "Â " vokommt, ersetzen _im aktuellen_ Element "&#xA0;" duch " ". Das ist sicherlich nicht das was du willst.

                    OK, machen wir es so einfach wie möglich:

                    <xsl:template match="text()">
                     <xsl:value-of select="translate(., 'Â ', ' ')"/>
                    <-- oder
                        <xsl:value-of select="normalize-space(translate(., 'Â ', ' '))"/> -->
                    </xsl:template>

                    Mit diesem Template überprüfst du jeden Text im Dokument automatisch.
                    Danach muss du nur darauf achten, dass du dort wo du Text ausgeben willst _nicht mehr_ value-of, sondern apply-templates verwendest.

                    <xsl:template match="xhtml:div">
                      xsl:copy
                       <xsl:apply-templates />
                      </xsl:copy>
                     </xsl:template>

                    Grüße
                    Thomas

                    1. Hi Thomas,

                      OK, machen wir es so einfach wie möglich:

                      <xsl:template match="text()">
                      <xsl:value-of select="translate(., 'Â ', ' ')"/>
                      <-- oder
                          <xsl:value-of select="normalize-space(translate(., 'Â ', ' '))"/> -->
                      </xsl:template>

                      Mit diesem Template überprüfst du jeden Text im Dokument automatisch.
                      Danach muss du nur darauf achten, dass du dort wo du Text ausgeben willst _nicht mehr_ value-of, sondern apply-templates verwendest.

                      <xsl:template match="xhtml:div">
                        xsl:copy
                         <xsl:apply-templates />
                        </xsl:copy>
                      </xsl:template>

                      Das hat super funktioniert und macht genau das was es soll :-).
                      Danke, danke, danke ...

                      Du hast mir wirklich sehr geholfen.

                      Gruß
                      joy

    2. Hallo Thomas,

      ich nochmal. Das mit dem

      <xsl:when test="string-length(translate(normalize-space(text()), ' ', '')) = 0"></xsl:when>

      funtkioniert doch. Hatte den falschen Text() bei mir angegeben. Vielen Dank für deine Hilfe.

      Gruß
      Joy