Stefan: "copy-of" kombiniert mit "translate" - wie geht's?

Hallo,

ich verusuche, eine XML-Datei in eine zweite zu konvertieren und dabei im Text eines Elementes ein Suchen & Ersetzen durchzuführen.

Ohne Suchen & Ersetzen sieht das so aus:

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

Funktioniert auch soweit. Nun möchte ich noch zusätzlich, dass der Text ersetzt wird. Wie man "translated", ist mir an sich schon klar, ich mache das z.B. so:

<xsl:variable name="string" select="." />
<xsl:variable name="source" select="abc" />
<xsl:variable name="target" select="ABC" />
<xsl:value-of select="translate($string, $source, $target)" />

Nur, wie baue ich das in mein copy-of ein?

Ist sicherlich ziehmlich einfach, aber ich google jetzt schon einige Stunden und komme nicht wirklich weiter. Bin noch recht frisch mit xsl ...

  1. Hallo,

    <xsl:value-of select="translate($string, $source, $target)" />

    Nur, wie baue ich das in mein copy-of ein?

    <xsl:copy-of select="translate(@*,$source,$target)"/>

    MfG, Thomas

    1. Hallo Thomas,

      » <xsl:copy-of select="translate(@*,$source,$target)"/>

      Das klappt leider nicht. Es wird nix translated und zudem fliegen die Attribute aus den Element-Tags und werden in den normalen Text geschrieben, z.B.:

      <para>EN-USabc</para>
      statt
      <para xml:lang="EN-US">ABC</para>

      <xsl:variable name="source" select="abc" />  
      <xsl:variable name="target" select="ABC" />  
        
      <xsl:template match="*">  
          <xsl:copy>  
              <xsl:copy-of select="translate(@*, $source, $target)"/>  
              <xsl:apply-templates />  
          </xsl:copy>  
      </xsl:template>
      

      ich vermute, das @* ist falsch, weil mit @ die Attribute eines Elementes geholt werden, oder?

      Danke,
      Stefan

      1. Hallo,

        Das klappt leider nicht. Es wird nix translated und zudem fliegen die Attribute aus den Element-Tags und werden in den normalen Text geschrieben, ...

        Den Selektor @* habe ich Deinem Code uebernommen, der ja angeblich funktionieren soll. Probiere es alternativ mit "@*|*" oder "@*|node()".

        Ansonsten mal pruefen, ob die Deklarartion von xsl:variable im richtigen Kontext erfolgt, sinnvollerweise global direkt nach xsl:stylesheet anlegen.

        MfG, Thomas

        1. Hallo Thomas,

          vielen Dank für Deine Mühen. Leider klappt es alles nicht, daher mal etwas ausführlicher ...

          Ich habe z.B. folgende XML-Datei (sample.xml):

            
          <?xml version="1.0" encoding="UTF-8"?>  
              <heading xml:lang="EN-US">abc</heading>  
              <para xml:lang="EN-US">abc</para>  
          
          

          Das dazugehörige xsl (sample.xsl) sieht so aus:

            
          <?xml version="1.0" encoding="utf-8"?>  
              <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>  
              <xsl:output encoding="UTF-8" indent="yes"/>  
            
              <xsl:variable name="source" select="abc" />  
              <xsl:variable name="target" select="ABC" />  
            
              <xsl:template match="*">  
                  <xsl:copy>  
                      <!-- <xsl:copy-of select="translate(@*, $source, $target)" /> -->  
                      <xsl:copy-of select="@*" />  
                      <xsl:apply-templates />  
                  </xsl:copy>  
              </xsl:template>  
            
          </xsl:stylesheet>  
          
          

          Das XSL dupliziert den kompletten Baum in eine neue Datei so wie er eben auch in der sample.xml ist, i.e. sie sieht nach der Transformation noch genauso aus wie vorher.
          Nun will ich aber zusätzlich die translation machen. Wenn ich aber
          <xsl:copy-of select="@*" />
          in
          <xsl:copy-of select="translate(@*, $source, $target)" />
          oder
          <xsl:copy-of select="translate(@*|*, $source, $target)" />
          oder
          <xsl:copy-of select="translate(@*|node(), $source, $target)" />
          ändere, führt das nicht zum Erfolg.
          Das Ergebnis ist dann

            
          <?xml version="1.0" encoding="UTF-8"?>  
              <heading>EN-USabc</heading>  
              <para>EN-USabc</para>  
          
          

          statt

            
          <?xml version="1.0" encoding="UTF-8"?>  
              <heading xml:lang="EN-US">ABC</heading>  
              <para xml:lang="EN-US">ABC</para>  
          
          

          Das Ganze ist also noch falsch, nur wie geht es richtig?

          Ratlos: Stefan.

          1. Hallo,

            Das Ganze ist also noch falsch, nur wie geht es richtig?

            Mein Fehler war die Anwendung von translate() auf die selektierten Knoten und nicht auf deren jeweiligen Inhalt.

            Bisher bin ich zu diesem Ergebnis gekommen, wobei die Attribute (noch) ausbleiben:

            <xsl:template match="@*|node()">  
              <xsl:copy>  
                <xsl:choose>  
                  <xsl:when test=". = text()">  
                    <xsl:value-of select="translate(.,'abc','ABC')"/>  
                  </xsl:when>  
                  <xsl:otherwise>  
                    <xsl:apply-templates select="@*|node()"/>  
                  </xsl:otherwise>  
                </xsl:choose>  
              </xsl:copy>  
            </xsl:template>
            

            MfG, Thomas

            1. Ja hallo! Dank Deiner Hilfe ist das jetzt der erste echte Erfolg, den ich seit heute Mittag erziele. Schade, dass die Attribute noch fehlen. Aber es klappt soweit schonmal, was mich echt glücklich macht. Wenn jetzt noch die Attribute übernommen würden, wäre das perfekt.

              Cheers,
              Stefan

              1. Hallo,

                Ja hallo! Dank Deiner Hilfe ist das jetzt der erste echte Erfolg, den ich seit heute Mittag erziele. Schade, dass die Attribute noch fehlen. Aber es klappt soweit schonmal, was mich echt glücklich macht. Wenn jetzt noch die Attribute übernommen würden, wäre das perfekt.

                <?xml version="1.0" encoding="utf-8"?>
                <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
                    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>

                <xsl:variable name="source" select="'abcdefghijklmnopqrstuvwxyz'" />
                    <xsl:variable name="target" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />

                <xsl:template match="*">
                        xsl:copy
                   <xsl:for-each select="@*">
                    <xsl:attribute name="{name()}">
                     <xsl:value-of select="translate(., $source, $target)" />
                    </xsl:attribute>
                   </xsl:for-each>
                            <xsl:apply-templates />
                        </xsl:copy>
                    </xsl:template>
                 <xsl:template match="text()">
                  <xsl:copy-of select="translate(., $source, $target)" />
                 </xsl:template>
                </xsl:stylesheet>

                Macht aus:

                <?xml version="1.0" encoding="UTF-8"?>
                <data>
                    <heading xml:lang="en-US" foo="defg">abc</heading>
                    <para xml:lang="EN-US">abc</para>
                </data>

                ein:

                <?xml version="1.0" encoding="UTF-8"?>
                <data>
                    <heading xml:lang="EN-US" foo="DEFG">ABC</heading>
                    <para xml:lang="EN-US">ABC</para>
                </data>

                Grüße
                Thomas (der andere ;-))

                1. Hallo Thomas der Andere :-)

                  das ist wirklich großartig. Mit dem xsl klappt es jetzt ganz wunderbar und alles ist genau so, wie ich es haben wollte. Werde mich nun nur noch morgen dran machen müssen, einen chose - when einzubauen, da nämlich in Abhängigkeit von einem Attributwert unterschiedliche Ersetzungen vorgenommen werden sollen. Aber das bekomme ich dann schon hin.

                  Auf jeden Fall noch einmal meinen ganz herzlichen Dank an Euch beide für die schnelle, abendliche und erfolgreiche Hilfe.

                  Danke,
                  Stefan

                2. Hallo,

                  <xsl:template match="*">
                          xsl:copy
                     <xsl:for-each select="@*">
                      <xsl:attribute name="{name()}">
                       ...

                  Da haette ich durchaus auch drauf kommen koennen, aber ich hatte mich zu sehr an der Identitaets-Transformation aufgehalten ...

                  Grüße
                  Thomas (der andere ;-))

                  Genau ;-)

                  1. Hallo Thomas,

                    <xsl:template match="*">
                            xsl:copy
                       <xsl:for-each select="@*">
                        <xsl:attribute name="{name()}">
                         ...

                    Da haette ich durchaus auch drauf kommen koennen, aber ich hatte mich zu sehr an der Identitaets-Transformation aufgehalten ...

                    Ich bin erst auch in der Falle vom 'template match=@*' gelaufen, was dann Probleme mit dem 'xml:' hatte :-)

                    Grüße
                    Thomas