Cam-Andi: xsl Attribute per Attributwert bestimmen

Hallo

im xsl muss ich die Job-Knoten durchlaufen und Knoteninhalt ausgeben wenn eine bestimmte Attributgruppe den Wert "1" hat. Eine Attributgruppe besteht u. a. immer aus

  1. oper.CUSTOM_DATA_0_NAME
  2. oper.CUSTOM_DATA_0_VALUE

Die Ziffer im Attributname variiert. Das Attribut mit Endung "Name" enthält die Kategorie. Hier "Ruestskizze". Dieses muss gefunden werden und dann das dazugehörige Attribut mit Endung "Value" geprüft werden. Soweit funktioniert das auch. Zusätzlich brauche ich nun noch den Wert für "Oldname". Dieser soll in der html-Tabelle ausgegeben werden. Zu finden im xsl unter Oldname Value. Wie kann das noch eingebaut werden?

<?xml version="1.0" encoding="UTF-8"?>
<JobList year="2019" month="11" day="03" hour="18" minute="38" >
  <Job id.seq="1"
    T.toolStringID="42011668"
    T.comment2="normal"
    oper.CUSTOM_DATA_0_NAME="Maschine"
    oper.CUSTOM_DATA_0_TYPE="nctool"
    oper.CUSTOM_DATA_0_VALUE="SFHermle C42 Auto"
    oper.CUSTOM_DATA_1_NAME="Vermessung"
    oper.CUSTOM_DATA_1_TYPE="nctool"
    oper.CUSTOM_DATA_1_VALUE="DBNull"
    oper.CUSTOM_DATA_2_NAME="OldName"
    oper.CUSTOM_DATA_2_TYPE="nctool"
    CUSTOM_DATA_2_VALUE="DBNull"
    CUSTOM_DATA_3_NAME="Bruchkontrolle"
    CUSTOM_DATA_3_TYPE="nctool"
    CUSTOM_DATA_3_VALUE="DBNull"
    CUSTOM_DATA_4_NAME="Ruestskizze"
    CUSTOM_DATA_4_TYPE="nctool"
    CUSTOM_DATA_4_VALUE="DBNull"
    CUSTOM_DATA_COUNT="5"
    TOOL_ID="42011668" />
  <Job id.seq="2"
    T.toolStringID="42011183"
    T.comment2="Sonder_WKZ_SF"
    CUSTOM_DATA_0_NAME="Maschine"
    CUSTOM_DATA_0_TYPE="nctool"
    CUSTOM_DATA_0_VALUE="SF Hermle C42 Auto"
    CUSTOM_DATA_1_NAME="Ruestskizze"
    CUSTOM_DATA_1_TYPE="nctool"
    CUSTOM_DATA_1_VALUE="1"
    CUSTOM_DATA_2_NAME="Vermessung"
    CUSTOM_DATA_2_TYPE="nctool"
    CUSTOM_DATA_2_VALUE="DBNull"
    CUSTOM_DATA_3_NAME="OldName"
    CUSTOM_DATA_3_TYPE="nctool"
    CUSTOM_DATA_3_VALUE="DBNull"
    CUSTOM_DATA_4_NAME="Bruchkontrolle"
    CUSTOM_DATA_4_TYPE="nctool"
    CUSTOM_DATA_4_VALUE="DBNull"
    CUSTOM_DATA_COUNT="5"
    TOOL_ID="42011183" />
  <Tool n.ref="1" toolStringID="42011183" />
  <Tool n.ref="1" toolStringID="42011668" />
</JobList>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" encoding="UTF-8" method="xml" />
  <xsl:param name="REPORT">joblist</xsl:param>
  <xsl:param name="LOCALE">de</xsl:param>
  <xsl:param name="FORMAT">html</xsl:param>
  <xsl:param name="CAPTURE">tool{fmt=EMF}{w=200}{h=280}{axis=ver}{style=2D}{dims=true}{blackAndWhite=true}{head=false}</xsl:param>
  <xsl:template match="/">
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <title>Rüst-Werkzeuge</title>
      </head>
      <body>
        <xsl:apply-templates />
      </body>
    </html>
  </xsl:template>
  <xsl:template match="JobList">
    <div style="font-family:Arial;width:1300px;">
    
      <!-- WKZ-Rüstskizzen =================================================== -->
        <table width="1300px" border="" style="margin-top:30px;">
        
          <xsl:for-each select="Job[not(@T.comment=preceding-sibling::Job/@T.comment)]">
          
            <xsl:variable name="varjob" select="."/>

                <xsl:for-each select="@*[name() = starts-with(name(), 'oper.CUSTOM_DATA')]">
                    <xsl:if test=". = 'Ruestskizze'">
                        <xsl:variable name="v1" select="substring(name(), 18, 1)"/>
                        <xsl:variable name="custdata_ruestskizze" select="concat('oper.CUSTOM_DATA_', $v1, '_VALUE')"/>
                        <xsl:for-each select="$varjob">
                            <xsl:if test="@*[name() = $custdata_ruestskizze] = '1'">
                          <table style="border-top:2px solid Silver;margin-top:30px;">
                            <thead>
                              <tr>
                                <td>
                                  <xsl:attribute name="id">
                                    <xsl:value-of select="concat('SpecIdentNr', @oper.TOOL_ID)"/>
                                  </xsl:attribute>
                                  <xsl:attribute name="style">
                                    <xsl:value-of select="'font-weight:bold; width:100px;'"/>
                                  </xsl:attribute>
                                  Old-Name
                                </td>
                                <td style="font-weight:bold; width:100px;">T-Nr</td>
                                <td style="font-weight:bold; width:400px;">Werkzeug</td>
                                <td style="font-weight:bold; width:200px;">Kommentar</td>
                              </tr>
                            </thead>
                            <tbody>
                                <tr style="font:12;">
                                  <td style="border-left:1px solid Silver;border-top:1px solid Silver;border-right:1px solid Silver;border-bottom:1px solid Silver;">
                                    Old-Name value
                                  </td>
                                  <td style="border-left:1px solid Silver;border-top:1px solid Silver;border-right:1px solid Silver;border-bottom:1px solid Silver;">
                                    <xsl:value-of select="@T.number" />
                                  </td>
                                  <td style="border-left:1px solid Silver;border-top:1px solid Silver;border-right:1px solid Silver;border-bottom:1px solid Silver;">
                                    <xsl:value-of select="@T.comment" />
                                  </td>
                                  <td style="border-left:1px solid Silver;border-top:1px solid Silver;border-right:1px solid Silver;border-bottom:1px solid Silver;">
                                    <xsl:value-of select="@T.comment2" />
                                  </td>
                                </tr>
                            </tbody>
                          </table>
                          <table>
                            <tr>
                              <td>
                                <img width="443" height="774">
                                    <xsl:attribute name="src" >
                                      <!-- https://stackoverflow.com/questions/44673224/xslt-for-each-with-multiple-lists -->
                                      <xsl:value-of select="../Tool[@toolStringID=current()/@oper.TOOL_ID]/@screen" />
                                    </xsl:attribute>
                                  </img>
                              </td>
                            </tr>
                          </table>
                          
                        </xsl:if>
                    </xsl:for-each>
                </xsl:if>
            </xsl:for-each>
          </xsl:for-each>
      </table>
    </div>
  </xsl:template>
</xsl:stylesheet>Quelltext hier

Danke und Grüße

  1. Hallo,

    Die Ziffer im Attributname variiert. Das Attribut mit Endung "Name" enthält die Kategorie. Hier "Ruestskizze". Dieses muss gefunden werden und dann das dazugehörige Attribut mit Endung "Value" geprüft werden. Soweit funktioniert das auch. Zusätzlich brauche ich nun noch den Wert für "Oldname". Dieser soll in der html-Tabelle ausgegeben werden. Zu finden im xsl unter Oldname Value. Wie kann das noch eingebaut werden?

    Soweit funktioniert das eben nicht. Die Transformation erzeugt nur das traurige HTML-Gerüst:

    <?xml version="1.0" encoding="UTF-8"?>
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <title>Rüst-Werkzeuge</title>
      </head>
      <body>
        <div xmlns="" style="font-family:Arial;width:1300px;">
          <table width="1300px" border="" style="margin-top:30px;" />
        </div>
      </body>
    </html>
    

    Schaue drüber, wenn der Code zumindest ansatzweise funktioniert und dann etwas Konkretes gesucht wird.

    Grüße,
    Thomas

    1. Hallo,

      Die Ziffer im Attributname variiert. Das Attribut mit Endung "Name" enthält die Kategorie. Hier "Ruestskizze". Dieses muss gefunden werden und dann das dazugehörige Attribut mit Endung "Value" geprüft werden. Soweit funktioniert das auch. Zusätzlich brauche ich nun noch den Wert für "Oldname". Dieser soll in der html-Tabelle ausgegeben werden. Zu finden im xsl unter Oldname Value. Wie kann das noch eingebaut werden?

      Soweit funktioniert das eben nicht. Die Transformation erzeugt nur das traurige HTML-Gerüst:

      <?xml version="1.0" encoding="UTF-8"?>
      <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
          <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
          <title>Rüst-Werkzeuge</title>
        </head>
        <body>
          <div xmlns="" style="font-family:Arial;width:1300px;">
            <table width="1300px" border="" style="margin-top:30px;" />
          </div>
        </body>
      </html>
      

      Schaue drüber, wenn der Code zumindest ansatzweise funktioniert und dann etwas Konkretes gesucht wird.

      Grüße,
      Thomas

      Hallo Thomas,

      vielen Dank für Deine Nachricht. Es kann gut sein dass die Transformation mit einem normalen oder üblichen Prozessor nicht läuft. Mein xsl gehört zu einem CAM-System mit eigenem "Report-Generator". Außerdem habe ich das Quell-xml gekürzt auf das wesentliche. Mein Problem ist eine Alternativlösung zu finden, also eine xsl-typische Lösung weil man keine Variablen in xsl neu beschreiben kann, also den Wert nicht nachträglich ändern kann. In C# zB würde ich vorgelagert eine for-each machen um das gesuchte Attribut zu finden um dann dessen Wert in eine Variable zu speichern. Dann könnte ich in der eigentlichen for-each den Variablen-Wert ausgeben.

      Danke und Gruß

      1. Hallo,

        In C# zB würde ich vorgelagert eine for-each machen um das gesuchte Attribut zu finden um dann dessen Wert in eine Variable zu speichern. Dann könnte ich in der eigentlichen for-each den Variablen-Wert ausgeben.

        Kann das, wie gesagt, so nicht nachvollziehen. Der Inhalt einer Variablen lässt sich aber durchaus dynamisch erzeugen:

        <xsl:variable name="var">
          <xsl:for-each select="...">
            <!-- hier Prüfungen via xsl:if oder
                 xsl:choose/xsl:when/xsl:otherwise
                 und Wertzuweisung -->
          </xsl:for-each>
        </xsl:variable>
        

        Grüße,
        Thomas

        1. Hallo Thomas,

          danke für Deine Antwort. Das bedeutet also dass Variablen-Definition und Wertzuweisung getrennt erfolgen kann? Das könnte mir weiterhelfen.

          Danke und Grüße

          1. Tach!

            Das bedeutet also dass Variablen-Definition und Wertzuweisung getrennt erfolgen kann? Das könnte mir weiterhelfen.

            Nein, der Name Variable ist etwas missverständlich, wenn man ihn von Programmiersprachen her kennt. Bei XSL ist eine Variable, was anderenorts eine Konstante ist. Variabel ist nur, dass je nach XML andere Werte drin stehen können. Aber während der Transformation ist der Wert konstant, nachdem er einmal zugewiesen wurde.

            Wenn die Ermittlung des Wertes ein komplexer Vorgang ist, kann der nicht separat notiert werden, sondern muss innerhalb des Bodys des Variablen-Elements notiert sein.

            dedlfix.

            1. Tach!

              Das bedeutet also dass Variablen-Definition und Wertzuweisung getrennt erfolgen kann? Das könnte mir weiterhelfen.

              Nein, der Name Variable ist etwas missverständlich, wenn man ihn von Programmiersprachen her kennt. Bei XSL ist eine Variable, was anderenorts eine Konstante ist. Variabel ist nur, dass je nach XML andere Werte drin stehen können. Aber während der Transformation ist der Wert konstant, nachdem er einmal zugewiesen wurde.

              Wenn die Ermittlung des Wertes ein komplexer Vorgang ist, kann der nicht separat notiert werden, sondern muss innerhalb des Bodys des Variablen-Elements notiert sein.

              dedlfix.

              Hi.

              Danke. Das mit der Konstante ist mir bewusst. Allerdings hatte ich so verstanden dass Definition und Wertzuweisung zusammen in einer Anweisung erfolgen muss.

              Gruß

              1. Tach!

                Das mit der Konstante ist mir bewusst. Allerdings hatte ich so verstanden dass Definition und Wertzuweisung zusammen in einer Anweisung erfolgen muss.

                Ja, so muss das. Es gibt keine Möglichkeit, den Wert erst zu ermitteln und dann zuzuweisen, denn dafür müsste er irgendwo zwischengespeichert werden. Dafür ist aber in XSL nichts vorgesehen. Die Erstellung der Variable muss ein einzelnes (aber beliebig komplexes) Element sein.

                dedlfix.

                1. Hallo,

                  man kann immerhin xsl:variable-Konstrukte zyklisch neu erzeugen, etwa in xsl:for-each.

                  Ansonsten lohnt ein Blick auf XSLT 2.0 / 3.0. Darin gibt es so genannte Sequenzen, denen man n-fach Werte oder Knoten zuweisen und auch wieder entfernen kann.

                  Arrays und Maps leisten ab XSLT 3.0 / XPath 3.1 noch viel mehr.

                  Grüße, Thomas

        2. Hallo,

          In C# zB würde ich vorgelagert eine for-each machen um das gesuchte Attribut zu finden um dann dessen Wert in eine Variable zu speichern. Dann könnte ich in der eigentlichen for-each den Variablen-Wert ausgeben.

          Kann das, wie gesagt, so nicht nachvollziehen. Der Inhalt einer Variablen lässt sich aber durchaus dynamisch erzeugen:

          <xsl:variable name="var">
            <xsl:for-each select="...">
              <!-- hier Prüfungen via xsl:if oder
                   xsl:choose/xsl:when/xsl:otherwise
                   und Wertzuweisung -->
            </xsl:for-each>
          </xsl:variable>
          

          Grüße,
          Thomas

          Hallo,

          danke. Das hat mich auf die richtige Spur gebracht. So geht es:

          <xsl:variable name="custdata_oldname">
            <xsl:for-each select="@*[name() = starts-with(name(), 'oper.CUSTOM_DATA')]">
              <xsl:if test=". = 'OldName'">
                <xsl:variable name="v2" select="substring(name(), 18, 1)"/>
                <xsl:value-of select="concat('oper.CUSTOM_DATA_', $v2, '_VALUE')" />
              </xsl:if>
            </xsl:for-each>
          </xsl:variable>
          

          Nun kann ich weiter hinten die Variable verwenden.

          Vielen Dank für die Hilfe.

          Gruß Andi