Wie kann ich mit XSL prüfen, ob ein Wert null oder leer ist?
Wenn beispielsweise categoryName
leer ist? Ich benutze ein , wenn ich ein Konstrukt wähle.
Zum Beispiel:
<xsl:choose>
<xsl:when test="categoryName !=null">
<xsl:value-of select="categoryName " />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="other" />
</xsl:otherwise>
</xsl:choose>
test="categoryName != ''"
Bearbeiten : Dies deckt meiner Meinung nach die wahrscheinlichste Interpretation von "[nicht] null oder leer" ab, wie aus der Frage abgeleitet, einschließlich ihrer Pseudo- Code und meine eigenen frühen Erfahrungen mit XSLT. D. h. "Was ist das Äquivalent des folgenden Java?":
!(categoryName == null || categoryName.equals(""))
Weitere Einzelheiten, z. B. die eindeutige Identifizierung von null und leer, finden Sie unter Johnveys Antwort unten und/oder die XSLT-Geige Ich habe diese Antwort angepasst, einschließlich der Option in Michael Kays Kommentar sowie der sechsten möglichen Interpretation.
Ohne weitere Informationen gehe ich von folgendem XML aus:
<group>
<item>
<id>item 1</id>
<CategoryName>blue</CategoryName>
</item>
<item>
<id>item 2</id>
<CategoryName></CategoryName>
</item>
<item>
<id>item 3</id>
</item>
...
</group>
Ein Beispiel für einen Anwendungsfall sieht folgendermaßen aus:
<xsl:for-each select="/group/item">
<xsl:if test="CategoryName">
<!-- will be instantiated for item #1 and item #2 -->
</xsl:if>
<xsl:if test="not(CategoryName)">
<!-- will be instantiated for item #3 -->
</xsl:if>
<xsl:if test="CategoryName != ''">
<!-- will be instantiated for item #1 -->
</xsl:if>
<xsl:if test="CategoryName = ''">
<!-- will be instantiated for item #2 -->
</xsl:if>
</xsl:for-each>
Von leeres Element:
Um zu testen, ob der Wert eines bestimmten Knotens leer ist
Es kommt darauf an, was du mit leer meinst.
not(node())
not(string(.))
not(normalize-space(.))
not(node()[not(self::comment())])
Wie wäre es mit?
test="not(normalize-space(categoryName)='')"
Die ersten beiden befassen sich mit dem Nullwert und die zweiten beiden befassen sich mit der leeren Zeichenfolge.
<xsl:if test="USER/FIRSTNAME">
USERNAME is not null
</xsl:if>
<xsl:if test="not(USER/FIRSTNAME)">
USERNAME is null
</xsl:if>
<xsl:if test="USER/FIRSTNAME=''">
USERNAME is empty string
</xsl:if>
<xsl:if test="USER/FIRSTNAME!=''">
USERNAME is not empty string
</xsl:if>
In einigen Fällen möchten Sie möglicherweise wissen, wann der Wert speziell null ist. Dies ist insbesondere dann erforderlich, wenn XML verwendet wird, das aus .NET-Objekten serialisiert wurde. Während die akzeptierte Antwort dafür funktioniert, gibt sie auch das gleiche Ergebnis zurück, wenn die Zeichenfolge leer oder leer ist, d. H. '', Sodass Sie nicht unterscheiden können.
<group>
<item>
<id>item 1</id>
<CategoryName xsi:nil="true" />
</item>
</group>
Sie können das Attribut also einfach testen.
<xsl:if test="CategoryName/@xsi:nil='true'">
Hello World.
</xsl:if>
Manchmal ist es notwendig, den genauen Status zu kennen, und Sie können nicht einfach überprüfen, ob CategoryName instanziiert ist, da im Gegensatz zu Javascript
<xsl:if test="CategoryName">
Hello World.
</xsl:if>
Gibt true für ein Nullelement zurück.
Wie kann ich mit XSL prüfen, ob ein Wert null oder leer ist?
Wenn zum Beispiel
categoryName
leer ist?
Dies ist wahrscheinlich der einfachste XPath-Ausdruck .
not(string(categoryName))
Erklärung :
Das Argument für die Funktion not()
ist false()
genau dann, wenn es kein categoryName
untergeordnetes Element ("null") des Kontextelements oder das (einzelne solche) categoryName
untergeordnete Element gibt hat einen Zeichenkettenwert - die leere Zeichenkette.
Ich benutze ein , wenn ich ein Konstrukt wähle.
Zum Beispiel:
<xsl:choose> <xsl:when test="categoryName !=null"> <xsl:value-of select="categoryName " /> </xsl:when> <xsl:otherwise> <xsl:value-of select="other" /> </xsl:otherwise> </xsl:choose>
Verwenden Sie in XSLT 2.0 :
<xsl:copy-of select="concat(categoryName, $vOther[not(string(current()/categoryName))])"/>
Hier ist ein vollständiges Beispiel :
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vOther" select="'Other'"/>
<xsl:template match="/">
<xsl:copy-of select="concat(categoryName,$vOther[not(string(current()/categoryName))])"/>
</xsl:template>
</xsl:stylesheet>
Wenn diese Umwandlung auf das folgende XML-Dokument angewendet wird:
<categoryName>X</categoryName>
das gewünschte, korrekte Ergebnis wird erzeugt :
X
Bei Anwendung auf dieses XML-Dokument :
<categoryName></categoryName>
oder dazu:
<categoryName/>
oder dazu
<somethingElse>Y</somethingElse>
das richtige Ergebnis wird erzeugt :
Other
Verwenden Sie in ähnlicher Weise diese XSLT 1.0 -Transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vOther" select="'Other'"/>
<xsl:template match="/">
<xsl:copy-of select=
"concat(categoryName, substring($vOther, 1 div not(string(categoryName))))"/>
</xsl:template>
</xsl:stylesheet>
Beachten Sie : Es werden überhaupt keine Bedingungen verwendet. Erfahren Sie in diesem Nice Pluralsight-Kurs, wie wichtig es ist, bedingte Konstrukte zu vermeiden:
Ich weiß, dass diese Frage alt ist, aber zwischen all den Antworten vermisse ich eine, die für diesen Anwendungsfall in der XSLT-Entwicklung üblich ist.
Ich stelle mir vor, dass der fehlende Code aus dem OP ungefähr so aussieht:
<xsl:template match="category">
<xsl:choose>
<xsl:when test="categoryName !=null">
<xsl:value-of select="categoryName " />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="other" />
</xsl:otherwise>
</xsl:choose>
</category>
Und dass die Eingabe ungefähr so aussieht:
<categories>
<category>
<categoryName>Books</categoryName>
</category>
<category>
<categoryName>Magazines</categoryName>
<categoryName>Periodicals</categoryName>
<categoryName>Journals</categoryName>
</category>
<category>
<categoryName><!-- please fill in category --></categoryName>
</category>
<category>
<categoryName />
</category>
<category />
</categories>
Ich gehe also davon aus, dass es null, leere, einzelne oder mehrere categoryName
Elemente geben kann. Um mit all diesen Fällen fertig zu werden, müssen Konstrukte im xsl:choose
-Stil verwendet werden, oder mit anderen Worten, es wird schnell chaotisch (umso mehr, wenn sich die Elemente auf verschiedenen Ebenen befinden können!). Eine typische Programmiersprache in XSLT ist die Verwendung von Vorlagen (daher das T in XSLT). Dabei handelt es sich um deklarative und nicht um zwingende Programmierung. Für diesen Anwendungsfall kann das ungefähr so aussehen:
<!-- positive test, any category with a valid categoryName -->
<xsl:template match="category[categoryName[text()]]">
<xsl:apply-templates />
</xsl:template>
<!-- any other category (without categoryName, "null", with comments etc) -->
<xsl:template match="category">
<xsl:text>Category: Other</xsl:text>
</xsl:template>
<!-- matching the categoryName itself for easy handling of multiple names -->
<xsl:template match="categoryName">
<xsl:text>Category: </xsl:text>
<xsl:value-of select="." />
</xsl:template>
Dies funktioniert (mit jeder XSLT-Version), da die erste übergeordnete Version eine höhere Priorität hat (sie hat ein Prädikat). Die passende "Fall-Through" -Vorlage, die zweite, fängt alles ab, was nicht gültig ist. Der dritte sorgt dann für die ordnungsgemäße Ausgabe des Wertes categoryName
.
Beachten Sie, dass in diesem Szenario keine spezifische Übereinstimmung mit categories
oder category
erforderlich ist, da der Prozessor automatisch alle untergeordneten Elemente verarbeitet, sofern nicht anders angegeben (in diesem Beispiel ist dies bei der zweiten und dritten Vorlage nicht der Fall) die Kinder weiterverarbeiten, weil sie keinen xsl:apply-templates
enthalten).
Dieser Ansatz ist einfacher erweiterbar als der imperative Ansatz, da er automatisch mehrere Kategorien behandelt und für andere Elemente oder Ausnahmen erweitert werden kann, indem nur eine weitere passende Vorlage hinzugefügt wird. Programmierung ohne if-Äste .
Hinweis: In XML gibt es kein null
. Es gibt xsi: nil , aber das wird selten verwendet, besonders selten in untypisierten Szenarien ohne irgendein Schema.
Wenn die Möglichkeit besteht, dass das Element im XML nicht vorhanden ist, würde ich sowohl prüfen, ob das Element vorhanden ist als auch ob die Zeichenfolgenlänge größer als Null ist:
<xsl:choose>
<xsl:when test="categoryName and string-length(categoryName) > 0">
<xsl:value-of select="categoryName " />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="other" />
</xsl:otherwise>
</xsl:choose>
Wenn für einen Knoten kein Wert in der Eingabe-XML verfügbar ist (siehe xpath),
<node>
<ErrorCode/>
</node>
die Funktion string () konvertiert in einen leeren Wert. Das funktioniert also gut:
string(/Node/ErrorCode) =''
So etwas funktioniert bei mir:
<xsl:choose>
<xsl:when test="string(number(categoryName)) = 'NaN'"> - </xsl:when>
<xsl:otherwise>
<xsl:number value="categoryName" />
</xsl:otherwise>
</xsl:choose>
Oder umgekehrt:
<xsl:choose>
<xsl:when test="string(number(categoryName)) != 'NaN'">
<xsl:number value="categoryName" />
</xsl:when>
<xsl:otherwise> - </xsl:otherwise>
</xsl:choose>
Hinweis: Wenn Sie keine Nullwerte überprüfen oder keine Nullwerte verarbeiten, gibt IE7 -2147483648 anstelle von NaN zurück.
Ich fand es eigentlich besser, nur auf String-Länge zu testen, da das Feld oft nicht null ist, sondern nur leer
<xsl: when test = "Zeichenfolgenlänge (Feld, das Sie testen möchten) <1">
Nach meiner Erfahrung ist der beste Weg:
<xsl:when test="not(string(categoryName))">
<xsl:value-of select="other" />
</xsl:when>
<otherwise>
<xsl:value-of select="categoryName" />
</otherwise>
Verwenden Sie einfach categoryName/text (). Ein solcher Test funktioniert gut mit <categoryName/>
und auch <categoryName></categoryName>
.
<xsl:choose>
<xsl:when test="categoryName/text()">
<xsl:value-of select="categoryName" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="other" />
</xsl:otherwise>
</xsl:choose>