Janine: xsl:if in Schleife, Ausgabe außerhalb

Hallo,

ich habe folgenden (stark vereinfachten) Code:

<check>
	<bpd name="000">
		<test name="010">false</test>
		<test name="020">true</test>
		<test name="030">true</test>
	</bpd>
	<bpd name="100">
		<test name="110">true</test>
		<test name="120">false</test>
		<test name="130">true</test>
	</bpd>
</check>

Nun möchte ich die Tests ausgeben, die "false" sind, damit man schnell die Fehler identifizieren und beheben kann. Das habe ich über eine Schleife gelöst und funktioniert auch wunderbar. Mein Problem ist nur, dass ich gerne für den Fall eine Ausgabe hätte, dass alle Tests "true" sind. Damit ich einen Satz drunter schreiben kann: "Alles in Ordnung, keine Fehler." Da habe ich aber einen Knoten im Kopf, wie man die Prüfung ohne Schleife durchführt, weil ich den Satz ja nicht 500x dastehen haben möchte.

Hier mein bisheriger Code:


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="xs" version="2.0">
  <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
  <xsl:template match="/">
  	<ul>
			<xsl:for-each select="/check/bpd/test">
				<xsl:if test="text() = 'false'">
					<li>
						<xsl:text>Test </xsl:text>
						<xsl:value-of select="../@name"/>
						<xsl:text>: Fehler bei </xsl:text>
						<xsl:value-of select="@name"/>
					</li>
				</xsl:if>
			</xsl:for-each>
		</ul>
		<xsl:if test="//test/text() != 'false'"> <!--Hier ist irgendwo der Fehler. Der Satz wird nämlich auch ausgegeben, wenn "false" irgendwo vorhanden ist.-->
			<p>Es sind keine fehlerhaften Verlinkungen vorhanden. :)</p>
		</xsl:if>
  </xsl:template>
</xsl:stylesheet>

Grüße, Janine↕️

akzeptierte Antworten

  1. Hallo Janine,

    ja, XSL führt häufig zu Knoten im Kopf wenn man nicht ständig damit arbeitet…

    Folgende Lösung ist mir eingefallen:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="xs" version="2.0">
    
        <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    
        <xsl:template match="/">
    
            <xsl:choose>
                <xsl:when test="/check/bpd/test[text() = 'false']">
                    <ul>
                        <xsl:for-each select="/check/bpd/test">
                            <xsl:if test="text() = 'false'">
                                <li>
                                    <xsl:text>Test </xsl:text>
    
                                    <xsl:value-of select="../@name"/>
                                    <xsl:text>: Fehler bei </xsl:text>
    
                                    <xsl:value-of select="@name"/>
                                </li>
                            </xsl:if>
                        </xsl:for-each>
                    </ul>
                </xsl:when>
                <xsl:otherwise>
                    <p>Es sind keine fehlerhaften Verlinkungen vorhanden. :)</p>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
    </xsl:stylesheet>
    

    Zu Erklärung: Mit <xsl:choose> wird zwischen zwei Alternativen unterschieden. Der Test beim <xsl:when> prüft ob es ein Element <test> mit dem Text false gibt. Wenn das der Fall ist, wird die Liste mit den Fehlern erzeugt. Andernfalls wird <xsl:otherwise> verwendet, und nur die Meldung ausgegeben, dass es keine Fehler gibt.

    Ich denke du sieht jetzt auch den Fehler in der Bedingung deines <xsl:if>: Die eckigen Klammern fehlen. Mit den eckigen Klammern kannst du bei XPath ganz allgemein Bedingungen für Element angegeben. Das funktioniert auch in Selektoren. Man könnte ggf. sogar auf if/choose verzichten und das ganze mit zwei Templates regeln:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="xs" version="2.0">
    
        <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    
        <xsl:template match="/check[not(./bpd/test/text() = 'false')]">
            <p>Es sind keine fehlerhaften Verlinkungen vorhanden. :)</p>
        </xsl:template>
    
        <xsl:template match="/check[./bpd/test/text() = 'false']">
            <ul>
                <xsl:for-each select="./bpd/test">
                    <xsl:if test="text() = 'false'">
                        <li>
                            <xsl:text>Test </xsl:text>
    
                            <xsl:value-of select="../@name"/>
                            <xsl:text>: Fehler bei </xsl:text>
    
                            <xsl:value-of select="@name"/>
                        </li>
                    </xsl:if>
                </xsl:for-each>
            </ul>
        </xsl:template>
    
    </xsl:stylesheet>
    

    Die Lösung ist entspricht etwas besser der deklarativen Natur von XSL, ist aber eventuell später schwerer nachvollziehbar.

    Beste Grüße

    Jens

    1. Hallo Jens,

      tausend Dank für deine schnelle Antwort! Werde ich gleich testen. Die Idee mit dem choose finde ich gut und leicht nachvollziehbar. Ein ähnliches Problem hatte ich letzte Woche auch, das kann ich evtl. über ein weiteres übergeordnetes choose lösen :) Danke!

      Grüße, Janine