XSLT'de bir dizenin boş veya boş olup olmadığını kontrol edin


325

XSL ile bir değerin boş olup olmadığını nasıl kontrol edebilirim ?

Örneğin categoryName, boşsa? Bir yapı seçerken kullanıyorum .

Örneğin:

<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>

Kod örneğini genişletebilir misiniz?
Nick Allen

Kullanım durumunuza bağlı olarak, muhtemelen xsl:whendüğüm testleri için kullanmak istemezsiniz . İle <xsl:template match="Category[categoryName[not(node())]]">...birlikte düşünün <xsl:template match="Category">.... İşlemci daha sonra sizin için doğru kararları alacak ve iş mantığını xsl:chooseartık iç içe olarak yazmanıza gerek yok. Çoğu durumda, eşleşen şablonların kullanılması stil sayfalarının yazılmasını kolaylaştırır.
Abel

Yanıtlar:


322
test="categoryName != ''"

Düzenleme : Bu, bence, sahte kod ve XSLT ile kendi erken deneyim de dahil olmak üzere, sorudan çıkarıldığı gibi "[boş] boş veya boş" en olası yorumunu kapsar. Yani, "Aşağıdaki Java'nın eşdeğeri nedir?":

!(categoryName == null || categoryName.equals(""))

Örneğin null ile boş arasındaki farkı kesin olarak belirlemek için aşağıdaki johnvey'in cevabına ve / veya Michael Kay'ın yorumundaki seçeneği ve olası altıncı yorumu içeren bu cevaptan uyarladığım XSLT ' kemanına' bakın .


14
Bu sınamanın ayrıntılı semantiği şöyledir: dize değeri boş bir dize olan en az bir categoryName öğesi varsa true değerini döndürür.
jelovirt

14
@jelovirt Boş bir dize DEĞİL en az bir categoryName olup olmadığını mı demek istediniz? (Ben bir xsl acemi değilim, bu yüzden soruma herhangi bir potansiyel aptallığı affet.)
joedevon

10
Bu cevap, kabul edilmiş ve yüksek oyla kabul edilmiş olsa da, çok yanıltıcıdır. Gerçekten "boş veya boş" ile ne demek istediğinize bağlı. CategoryName yoksa veya sıfır uzunluk değerine sahipse başarılı olan bir test istiyorsanız, kullanmalısınız test="not(categoryName = '')". CategoryName öğesi yoksa, verilen yanıt false değerini döndürür. Bu, soruyu yorumlamamda yanlış bir yanıt yapar.
Michael Kay

2
@MichaelKay: Daha fazla ayrıntı sağlamak için cevabı güncelledim. Yorum ve Saxon XSLT işlemci için teşekkürler!
steamer25

<xsl:for-each select="root/*[matches(name(.), 'grp')]">VS2010'da kullanılabilmesi için nasıl çeviri yapabilirim?
Si8

276

Başka herhangi bir bilgi yoksa, aşağıdaki XML olduğunu varsayacağım:

<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>

Örnek bir kullanım örneği şöyle görünecektir:

<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>

Örneklerini nasıl test edersiniz </CategoryName>? , boş string testleri bunun için çalışmıyor
raffian

3
Her ifadenin nasıl sonuçlandığını göstermek için birden fazla örnek eklediğiniz için teşekkür ederiz.
doubleJ7

1
@ raffian: XSLT'de veya ilgili teknolojilerde (XQuery, DOM, XDM, Şema vb.), bitiş etiketleri ayrı varlıklar olarak kabul edilmez. Bunun yerine, yalnızca başlangıç ​​etiketi ve bitiş etiketi arasındaki düğüm olan düğümlerle veya öğelerle ilgilenirsiniz. Kısacası, test etmenin bir yolu yoktur ve buna da gerek yoktur </CategoryName>.
Abel

4
Soruyu özellikle bu cevap için oynadım ve soru oldukça eski olsa da, bu seçilen cevap olmayı çok daha hak ediyor gibi görünüyor
Patrick

68

Gönderen Boş Elemanda :

Belirli bir düğümün değerinin boş olup olmadığını test etmek için

Boş olarak ne demek istediğine bağlı.

  • Alt düğüm içermez: not(node())
  • Metin içeriği yok: not(string(.))
  • Boşluk dışında bir metin içermez: not(normalize-space(.))
  • Yorumlar dışında hiçbir şey içermez: not(node()[not(self::comment())])

2
+1. Bazı notlar. İlk madde işareti aynı zamanda bir düğüm olan metin içeriğini de test eder. İkinci mermi noktası, herhangi bir derinlikteki herhangi bir metin düğümü için test eder, mevcut düğümün metin içermediğini, ancak başka düğümler içerebileceğini bilmek istiyorsanız, kullanabilirsiniz not(text()). İkinci merminize bir alternatif de var not(.//text()). Son merminizin gösterdiği gibi: "hiçlik";) düşünmenin birçok yolu vardır.
Abel

Çok pratik: Bir dizenin boş olup olmadığını test etmek için dizenin kendisini test edebilirsiniz! if ($mystring) then ... else ...
Felix Dombek

22

Ne dersin?

test="not(normalize-space(categoryName)='')"

1
Harika çalışıyor. İçinde bir yorum olduğunda <categoryName> <!-- some comment --> </categoryName>ve başka türlü anlamlı bir metin olmasa bile , bu hala değerlendirilirtrue
rustyx

9

İlk ikisi boş değerle, ikinci ikisi boş dizeyle ilgilidir.

<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>

1
Korkunç. Birden fazla kullanıcı veya birden çok ad varsa ne olur? İstediğinizi xsl:apply-templateselde etmek için şablonları kullanın ve eşleştirin, çok daha kolay.
Abel

7

Bazı durumlarda, özellikle .NET nesnelerinden serileştirilmiş XML kullanırken gerekli olan değerin özellikle null olduğunu bilmek isteyebilirsiniz. Kabul edilen cevap bunun için çalışırken, dize boş veya boş olduğunda da aynı sonucu döndürür, yani '', bu yüzden ayırt edemezsiniz.

<group>
    <item>
        <id>item 1</id>
        <CategoryName xsi:nil="true" />
    </item>
</group>

Böylece özelliği test edebilirsiniz.

<xsl:if test="CategoryName/@xsi:nil='true'">
   Hello World.
</xsl:if>

Bazen tam durumu bilmek gerekir ve sadece Javascript deyin aksine KategoriAdı somut örnek olup olmadığını kontrol edemezsiniz

<xsl:if test="CategoryName">
   Hello World.
</xsl:if>

Boş bir öğe için true değerini döndürür.


6

Bu sorunun eski olduğunu biliyorum, ancak tüm cevaplar arasında, XSLT geliştirmedeki bu kullanım durumu için ortak bir yaklaşım olanı özlüyorum.

Ben OP eksik kodu böyle bir şey görünüyor hayal ediyorum:

<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>

Ve girdinin şöyle görünmesi:

<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>

Yani, sıfır, boş, tek veya birden fazla categoryNameeleman olabileceğini varsayıyorum . Tüm bu durumlarla xsl:choose-style yapıları kullanarak veya başka bir deyişle, zorunlulukla uğraşmak hızla dağınık hale gelir (hatta unsurlar farklı seviyelerde olabilirse!). XSLT'deki tipik bir programlama deyimi, şablonlar kullanır (dolayısıyla XSLT'deki T), zorunlu programlama değildir, zorunlu değildir (işlemciye ne yapması gerektiğini söylemezsiniz, sadece belirli koşullar karşılandığında hangi çıktıyı istediğinizi söylersiniz). Bu kullanım durumunda, bu aşağıdaki gibi görünebilir:

<!-- 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>

Bu (herhangi bir XSLT sürümü ile) çalışır, çünkü yukarıdaki ilkinin daha yüksek bir önceliği vardır (bir yüklemi vardır). "Düşen" eşleme şablonu, ikincisi, geçerli olmayan her şeyi yakalar. Üçüncüsü, categoryNamedeğerin uygun bir şekilde çıkarılmasına özen gösterir .

Bu senaryoya göre specifially maç için gerek olmadığını Not categoriesveya categoryhiç olmadığından işlemci otomatik olarak tüm çocukları işleyecek çünkü siz başka bir şey olmadıkça, (bu örnekte, ikinci ve üçüncü şablon, çocuk ileri değil işlemi yapmak xsl:apply-templatesiçinde onları).

Bu yaklaşım, zorunlu yaklaşımdan daha kolay genişletilebilir, çünkü otomatik olarak birden fazla kategoriyle ilgilenir ve sadece başka bir eşleşen şablon ekleyerek diğer öğeler veya istisnalar için genişletilebilir. İflasız programlama .

Not: nullXML'de olduğu gibi bir şey yoktur . Orada xsi: nil , ama bu nadiren bir çeşit şema olmadan türsüz senaryolarda özellikle nadiren kullanılır.


1
Tebrikler " If- branksız Programlama " dan bahsedenler . Bunun önemini anlayamayan bazı insanlar var. Hepsi için bu konuda çok güzel bir Pluralsight kursuna bir link : Zoran Horvat tarafından " .NET'te Taktik Tasarım Desenleri: Kontrol Akışı ": app.pluralsight.com/library/courses/… Mutlaka okunmalı!
Dimitre Novatchev

5

XSL ile bir değerin boş olup olmadığını nasıl kontrol edebilirim?

Örneğin categoryName, boşsa?

Bu muhtemelen en basit XPath ifadesidir (kabul edilen yanıttaki ifade tam tersi için bir test sağlar ve reddedilirse daha uzun olur):

not(string(categoryName))

Açıklama :

not()Yukarıdaki işlevin bağımsız değişkeni , false()tam olarak categoryNamebağlam öğesinin alt öğesi ("null") olmadığında veya (böyle tek) categoryNamealt öğenin dize değeri - boş dize olduğu zamandır.

Bir yapı seçerken kullanıyorum .

Örneğin:

<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'da :

<xsl:copy-of select="concat(categoryName,  $vOther[not(string(current()/categoryName))])"/>

İşte tam bir örnek :

<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>

Bu dönüşüm aşağıdaki XML belgesine uygulandığında:

<categoryName>X</categoryName>

istenen, doğru sonuç üretilir :

X

Bu XML belgesine uygulandığında :

<categoryName></categoryName>

veya bunun üzerinde:

<categoryName/>

ya da bunun üzerinde

<somethingElse>Y</somethingElse>

doğru sonuç üretilir :

Other

Benzer şekilde, bu XSLT 1.0 dönüşümünü kullanın :

<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>

Unutmayın : Hiçbir koşul kullanılmaz. Bu güzel Çoğul Görüş kursunda koşullu yapılardan kaçınmanın önemi hakkında daha fazla bilgi edinin:

" .NET'te Taktik Tasarım Kalıpları: Kontrol Akışı "


Merhaba Dimitre, 1.0 için çözümüne ihtiyacım var, bu yüzden sahip olduğum her etikette kodlamam gerekiyor mu ya da tüm XML için etkilemek için daha basit bir yol var mı?
zyberjock

@zyberjock, Ne sorduğunuz belirsiz. Lütfen bir soru gönderin ve bana bağlantı içeren bir yorum gönderin. İyi bir soru sormak için yönergeleri izleyin.
Dimitre Novatchev

Merhaba @Dimitre, burada bir soru gönderdim stackoverflow.com/questions/38150093/…
zyberjock

4

Öğenin XML'de bulunma olasılığı varsa, öğenin mevcut olduğunu ve dize uzunluğunun sıfırdan büyük olduğunu test ederim:

<xsl:choose>
    <xsl:when test="categoryName and string-length(categoryName) &gt; 0">
        <xsl:value-of select="categoryName " />
    </xsl:when>
    <xsl:otherwise>
        <xsl:value-of select="other" />
    </xsl:otherwise>
</xsl:choose>

3
Boş bir düğüm kümesinin dize değeri ( geçerli bağlamda alt öğe categoryNameolmadığında XPath ifadesinin size verdiği değer categoryName) boş dize olarak tanımlanır, bu nedenle bu gereksizdir - öğe string-length(categoryName)yoksa sıfırdır categoryName.
Ian Roberts

3

Bir düğümün xml girişinde xpath altındaki gibi bir değeri yoksa,

<node>
    <ErrorCode/>
</node>

string () işlevi boş değere dönüştürülür. Yani bu iyi çalışıyor:

string(/Node/ErrorCode) =''

2

Bunun gibi bir şey benim için çalışıyor:

<xsl:choose>
  <xsl:when test="string(number(categoryName)) = 'NaN'"> - </xsl:when> 
  <xsl:otherwise> 
    <xsl:number value="categoryName" />
  </xsl:otherwise>
</xsl:choose>

Ya da tam tersi:

<xsl:choose>
  <xsl:when test="string(number(categoryName)) != 'NaN'">
    <xsl:number value="categoryName" />
  </xsl:when> 
  <xsl:otherwise> - </xsl:otherwise>
</xsl:choose>

Not: Boş değerleri kontrol etmez veya boş değerleri işlemezseniz IE7, NaN yerine -2147483648 değerini döndürür.


1

Aslında daha iyi buldum sadece dize uzunluğu için test alan çoğu kez boş değil, sadece boş

<xsl: when test = "string-length (test etmek istediğiniz alan) <1">


0

Deneyimlerime göre en iyi yol:

<xsl:when test="not(string(categoryName))">
    <xsl:value-of select="other" />
</xsl:when>
<otherwise>
    <xsl:value-of select="categoryName" />
</otherwise>

0

Basit categoryName / text () kullan Bu tür testler iyi <categoryName/>ve aynı zamanda iyi çalışır <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>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.