XSLTで文字列がnullまたは空かどうかを確認します
質問
XSL を使用して、値がnullまたは空かどうかを確認するにはどうすればよいですか?
たとえば、categoryName
が空の場合コンストラクトを選択するときに使用しています。
例:
<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 != ''"
編集:これは、<!> quot; [not] null or empty <!> quot;の最も可能性の高い解釈をカバーしています。質問から推測されるように、擬似コードとXSLTでの私自身の初期の経験を含みます。つまり、<!> quot;次のJavaと同等のものは何ですか?<!> quot;:
!(categoryName == null || categoryName.equals(""))
たとえば、nullと空を明確に識別するなどの詳細については、下記のjohnveyの回答および/または XSLT「フィドル」私はその答えから改造しました。これには、マイケル・ケイのコメントのオプションと6番目の可能性が含まれています解釈。
他のヒント
他の情報がない場合、次のXMLを想定します。
<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>
サンプルの使用例は次のようになります。
<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>
空の要素 から:
特定のノードの値が空かどうかをテストするには
空の意味に依存します。
- 子ノードを含まない:
not(node())
- テキストコンテンツを含まない:
not(string(.))
- 空白以外のテキストを含まない:
not(normalize-space(.))
- コメント以外は何も含まれていません:
not(node()[not(self::comment())])
どうですか?
test="not(normalize-space(categoryName)='')"
最初の2つはnull値を扱い、次の2つは空の文字列を扱います。
<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>
場合によっては、値が特にnullであるかどうかを知りたい場合があります。これは、.NETオブジェクトからシリアル化されたXMLを使用する場合に特に必要です。受け入れられた答えはこれに対して機能しますが、文字列が空白または空の場合も同じ結果を返します、つまり ''ですので、区別できません。
<group>
<item>
<id>item 1</id>
<CategoryName xsi:nil="true" />
</item>
</group>
したがって、単純に属性をテストできます。
<xsl:if test="CategoryName/@xsi:nil='true'">
Hello World.
</xsl:if>
正確な状態を知ることが必要な場合があります。Javascriptとは異なり、CategoryNameがインスタンス化されているかどうかを単純に確認することはできません
<xsl:if test="CategoryName">
Hello World.
</xsl:if>
null要素に対してtrueを返します。
XMLに要素が存在しない可能性がある場合、要素が存在することと、string-lengthがゼロより大きいことの両方をテストします。
<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>
この質問は古いことは知っていますが、すべての答えの中で、XSLT開発におけるこのユースケースの一般的なアプローチであるものが恋しいです。
OPから欠落しているコードが次のように見えることを想像しています:
<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>
そして、入力は次のようになります:
<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>
つまり、ゼロ、空、単一、または複数のcategoryName
要素が存在すると想定しています。 xsl:choose
-style構造を使用してこれらのすべてのケースを処理する、つまり、命令的に、すぐに面倒になります(要素が異なるレベルにある場合はさらにそうです!)。 XSLTの典型的なプログラミングのイディオムは、宣言型プログラミングであり、命令型ではないテンプレート(XSLTのTです)を使用しています(特定の条件が満たされた場合に出力する内容をプロセッサに指示するだけです)。このユースケースでは、次のようになります。
<!-- 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>
これは(上記のXSLTバージョンで)動作します。これは、上記の最初のものが優先順位が高いためです(述語があります)。 <!> quot; fall-through <!> quot;一致するテンプレート、2番目のテンプレートは、無効なものをすべてキャッチします。 3番目のものは、適切な方法でcategories
値を出力します。
このシナリオでは、特に指定しない限り、プロセッサがすべての子を自動的に処理するため、このシナリオではcategory
またはxsl:apply-templates
を特に一致させる必要はありません(この例では、2番目と3番目のテンプレートはnull
が存在しないため、子を処理します。)
このアプローチは、複数のカテゴリを自動的に処理し、別の一致するテンプレートを追加するだけで他の要素または例外用に拡張できるため、命令型アプローチよりも簡単に拡張できます。 if-branchesを使用しないプログラミング。
注:XMLには<=>などはありません。 xsi:nil がありますが、ほとんど使用されておらず、特に型付けされていない場合はほとんどありません何らかのスキーマのないシナリオ。
XSLで値がnullまたは空かどうかを確認するにはどうすればよいですか?
たとえば、
categoryName
が空の場合
これはおそらく最も単純なXPath式です(受け入れられた答えの式は反対のテストを提供し、否定される場合はより長くなります):
not(string(categoryName))
説明:
上記のnot()
関数への引数は、コンテキスト項目のfalse()
子(<!> quot; null <!> quot;)がない場合、または(単一の)< =>子には文字列値-空の文字列があります。
選択時にコンストラクトを使用しています。
例:
<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>
XSLT 2.0での使用:
<xsl:copy-of select="concat(categoryName, $vOther[not(string(current()/categoryName))])"/>
完全な例は次のとおりです:
<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>
この変換が次のXMLドキュメントに適用される場合:
<categoryName>X</categoryName>
必要な正しい結果が生成されます:
X
このXMLドキュメントに適用される場合:
<categoryName></categoryName>
またはこれについて:
<categoryName/>
またはこれについて
<somethingElse>Y</somethingElse>
正しい結果が生成されます:
Other
同様に、この XSLT 1.0 変換を使用します:
<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>
注意事項:条件はまったく使用されません。この素敵なPluralsightコースで条件付き構造を避けることの重要性について詳しく学んでください:
xpathのような入力xmlで使用可能な値がノードにない場合、
<node>
<ErrorCode/>
</node>
string()関数は空の値に変換します。したがって、これは正常に動作します:
string(/Node/ErrorCode) =''
このようなことは私にとってはうまくいく:
<xsl:choose>
<xsl:when test="string(number(categoryName)) = 'NaN'"> - </xsl:when>
<xsl:otherwise>
<xsl:number value="categoryName" />
</xsl:otherwise>
</xsl:choose>
またはその逆:
<xsl:choose>
<xsl:when test="string(number(categoryName)) != 'NaN'">
<xsl:number value="categoryName" />
</xsl:when>
<xsl:otherwise> - </xsl:otherwise>
</xsl:choose>
注:null値を確認したり、null値を処理しない場合、IE7はNaNではなく-2147483648を返します。
実際には、フィールドがヌルではなく空であることが多いため、文字列の長さをテストするだけでよいことがわかりました
<!> lt; xsl:when test = <!> quot; string-length(field-you-want-to-test)<!> lt; 1 <!> quot; <!> gt;
私の経験では、最良の方法は次のとおりです。
<xsl:when test="not(string(categoryName))">
<xsl:value-of select="other" />
</xsl:when>
<otherwise>
<xsl:value-of select="categoryName" />
</otherwise>
単純なcategoryName / text()を使用するこのようなテストは、<categoryName/>
および<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>