Kiểm tra xem một chuỗi là null hoặc trống trong XSLT


325

Làm cách nào để kiểm tra xem giá trị là null hay rỗng với XSL ?

Chẳng hạn, nếu categoryNametrống? Tôi đang sử dụng khi chọn cấu trúc.

Ví dụ:

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

Bạn có thể mở rộng ví dụ mã?
Nick Allen

Tùy thuộc vào trường hợp sử dụng của bạn, có lẽ bạn không muốn sử dụng xsl:whencho các bài kiểm tra nút. Cân nhắc <xsl:template match="Category[categoryName[not(node())]]">...cùng với a <xsl:template match="Category">.... Sau đó, bộ xử lý sẽ đưa ra quyết định chính xác cho bạn và bạn không cần phải viết ra logic nghiệp vụ trong lồng nhau xsl:choosenữa. Trong nhiều trường hợp, sử dụng các mẫu phù hợp làm cho việc viết biểu định kiểu dễ dàng hơn.
Abel

Câu trả lời:


322
test="categoryName != ''"

Chỉnh sửa : Điều này bao gồm cách giải thích có khả năng nhất, theo ý kiến ​​của tôi, về "[không] rỗng hoặc trống rỗng" như được suy ra từ câu hỏi, bao gồm mã giả và trải nghiệm ban đầu của tôi với XSLT. Tức là, "Tương đương với Java sau đây là gì?":

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

Để biết thêm chi tiết, ví dụ, xác định rõ ràng null so với trống, hãy xem câu trả lời của johnvey bên dưới và / hoặc 'fiddle' XSLT mà tôi đã điều chỉnh từ câu trả lời đó, bao gồm tùy chọn trong nhận xét của Michael Kay cũng như cách giải thích thứ sáu có thể.


14
Các ngữ nghĩa chi tiết của bài kiểm tra này là: return true nếu có ít nhất một phần tử categoryName có giá trị chuỗi là một chuỗi rỗng.
jelovirt

14
@jelovirt Ý bạn là muốn nói nếu có ít nhất một danh mục Tên đó KHÔNG phải là một chuỗi rỗng? (Tôi là một người mới chơi xsl, vì vậy hãy tha thứ cho bất kỳ sự ngu ngốc tiềm tàng nào đối với câu hỏi của tôi.)
joedevon

10
Câu trả lời này, trong khi được chấp nhận và đánh giá cao, cũng rất sai lệch. Nó thực sự phụ thuộc vào những gì bạn có nghĩa là "không hoặc trống rỗng". Nếu bạn muốn thử nghiệm thành công nếu categoryName vắng mặt hoặc xuất hiện với giá trị độ dài bằng không, bạn nên sử dụng test="not(categoryName = '')". Câu trả lời được cung cấp sẽ trả về false nếu phần tử categoryName không có, điều này theo cách hiểu của tôi về câu hỏi làm cho nó trở thành một câu trả lời sai.
Michael Kay

2
@MichaelKay: Tôi đã cập nhật câu trả lời để cung cấp thêm chi tiết. Cảm ơn đã nhận xét và cho bộ xử lý Saxon XSLT!
hấp25

Làm thế nào tôi có thể dịch <xsl:for-each select="root/*[matches(name(.), 'grp')]">để nó có thể được sử dụng trong VS2010?
Si8

276

Không có bất kỳ thông tin nào khác, tôi sẽ giả sử XML sau:

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

Một trường hợp sử dụng mẫu sẽ trông như sau:

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

Làm thế nào để bạn kiểm tra cho các trường hợp </CategoryName>? , kiểm tra chuỗi trống không hoạt động cho việc này
raffian

3
Chúng tôi đánh giá cao rằng bạn đã bao gồm nhiều ví dụ để hiển thị kết quả của từng biểu thức.
doubleJ

1
@raffian: trong XSLT hoặc các công nghệ liên quan (XQuery, DOM, XDM, Schema, v.v.), thẻ kết thúc không được coi là các thực thể riêng biệt. Thay vào đó, bạn chỉ xử lý các nút hoặc các thành phần trong trường hợp này, đó là toàn bộ giữa thẻ bắt đầu và thẻ kết thúc. Nói tóm lại, không có cách nào để kiểm tra </CategoryName>, cũng không cần thiết.
Abel

4
Tôi đã đánh dấu câu hỏi đặc biệt cho câu trả lời này và trong khi câu hỏi khá cũ, thì câu hỏi này có vẻ xứng đáng hơn là câu trả lời được chọn
Patrick

68

Từ phần tử rỗng :

Để kiểm tra xem giá trị của một nút nào đó có trống không

Nó phụ thuộc vào những gì bạn có nghĩa là trống rỗng.

  • Không chứa các nút con: not(node())
  • Không chứa nội dung văn bản: not(string(.))
  • Không chứa văn bản nào ngoài khoảng trắng: not(normalize-space(.))
  • Không chứa gì ngoại trừ ý kiến: not(node()[not(self::comment())])

2
+1. Một số lưu ý. Đạn đầu tiên cũng kiểm tra nội dung văn bản, cũng là một nút. Kiểm tra dấu đầu dòng thứ hai cho bất kỳ nút văn bản nào ở bất kỳ độ sâu nào, nếu bạn muốn biết nếu nút hiện tại không chứa văn bản, nhưng có thể chứa các nút khác, bạn có thể sử dụng not(text()). Một thay thế cho viên đạn thứ 2 của bạn cũng là not(.//text()). Như viên đạn cuối cùng của bạn cho thấy: có nhiều cách để xem xét "hư vô";).
Abel

Rất thực tế: Để kiểm tra xem một chuỗi là không có sản phẩm nào, bạn chỉ có thể kiểm tra chuỗi chính nó! if ($mystring) then ... else ...
Felix Dombek

22

Thế còn?

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

1
Điều này làm việc tuyệt vời. Ngay cả khi có một bình luận bên trong <categoryName> <!-- some comment --> </categoryName>và mặt khác không có văn bản có ý nghĩa, điều này vẫn đánh giátrue
rustyx

9

Hai giao dịch đầu tiên với giá trị null và hai giao dịch thứ hai với chuỗi rỗng.

<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
Đáng sợ. Nếu có nhiều người dùng hoặc nhiều tên thì sao? Sử dụng xsl:apply-templatesvà kết hợp các mẫu để có được những gì bạn muốn, dễ dàng hơn nhiều.
Abel

7

Trong một số trường hợp, bạn có thể muốn biết khi nào giá trị cụ thể là null, điều này đặc biệt cần thiết khi sử dụng XML đã được tuần tự hóa từ các đối tượng .NET. Mặc dù câu trả lời được chấp nhận hoạt động cho điều này, nó cũng trả về kết quả tương tự khi chuỗi trống hoặc trống, tức là '', vì vậy bạn không thể phân biệt được.

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

Vì vậy, bạn có thể chỉ cần kiểm tra thuộc tính.

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

Đôi khi, cần phải biết chính xác trạng thái và bạn không thể kiểm tra xem CategoryName có được khởi tạo hay không, vì không giống như Javascript.

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

Sẽ trả về true cho phần tử null.


6

Tôi biết câu hỏi này đã cũ, nhưng giữa tất cả các câu trả lời, tôi bỏ lỡ một câu hỏi là cách tiếp cận phổ biến cho trường hợp sử dụng này trong phát triển XSLT.

Tôi đang tưởng tượng rằng mã bị thiếu từ OP trông giống như thế này:

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

Và rằng đầu vào trông giống như thế này:

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

Tức là, tôi cho rằng có thể có 0, trống, đơn hoặc nhiều categoryNamephần tử. Để giải quyết tất cả các trường hợp này bằng xsl:choosecách sử dụng các cấu trúc kiểu, hay nói cách khác, bắt buộc phải nhanh chóng trở nên lộn xộn (thậm chí nhiều hơn nếu các yếu tố có thể ở các cấp độ khác nhau!). Một thành ngữ lập trình điển hình trong XSLT là sử dụng các mẫu (do đó T trong XSLT), đó là lập trình khai báo, không bắt buộc (bạn không nói cho bộ xử lý biết phải làm gì, bạn chỉ cần nói bạn muốn đầu ra nếu điều kiện nhất định được đáp ứng). Đối với trường hợp sử dụng này, có thể trông giống như sau:

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

Điều này hoạt động (với bất kỳ phiên bản XSLT nào), vì phiên bản đầu tiên ở trên có độ ưu tiên cao hơn (nó có một vị ngữ). Mẫu phù hợp "rơi qua", mẫu thứ hai, nắm bắt bất cứ điều gì không hợp lệ. Cái thứ ba sau đó đảm nhận việc xuất racategoryName giá trị một cách thích hợp.

Lưu ý rằng trong kịch bản này, không cần phải khớp cụ thể categorieshoặc categorybởi vì bộ xử lý sẽ tự động xử lý tất cả trẻ em, trừ khi chúng tôi nói khác (trong ví dụ này, mẫu thứ hai và thứ ba không xử lý thêm cho trẻ em, vì không cóxsl:apply-templates trong họ).

Cách tiếp cận này dễ dàng mở rộng hơn cách tiếp cận bắt buộc, bởi vì nó tự động xử lý nhiều danh mục và nó có thể được mở rộng cho các yếu tố hoặc ngoại lệ khác bằng cách chỉ cần thêm một mẫu phù hợp khác. Lập trình mà không có nhánh if .

Lưu ý: không có thứ như nulltrong XML. Có xsi: nil , nhưng điều đó hiếm khi được sử dụng, đặc biệt hiếm khi trong các tình huống chưa được xử lý mà không có lược đồ nào đó.


1
Chúc mừng bạn đã đề cập đến " Lập trình mà không có nhánh ". Có một số người không hiểu tầm quan trọng của việc này. Đối với tất cả chúng ở đây là một liên kết đến một khóa học Pluralsight rất hay về chủ đề này: " Các mẫu thiết kế chiến thuật trong .NET: Kiểm soát dòng chảy " của Zoran Horvat: app.pluralsight.com/l Library / cferences / Khăn A phải đọc!
Dimitre Novatchev

5

Làm cách nào để kiểm tra xem giá trị là null hay rỗng với XSL?

Chẳng hạn, nếu categoryNametrống?

Đây có lẽ là biểu thức XPath đơn giản nhất (câu trả lời được chấp nhận cung cấp một bài kiểm tra ngược lại và sẽ dài hơn, nếu bị phủ định):

not(string(categoryName))

Giải thích :

Đối số cho not()hàm trên là false()chính xác khi không có categoryNamecon ("null") của mục ngữ cảnh hoặc con (đơn lẻ) categoryNamecó giá trị chuỗi - chuỗi rỗng.

Tôi đang sử dụng khi lựa chọn cấu trúc.

Ví dụ:

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

Trong XSLT 2.0, sử dụng :

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

Dưới đây là một ví dụ hoàn chỉnh :

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

Khi chuyển đổi này được áp dụng trên tài liệu XML sau:

<categoryName>X</categoryName>

kết quả mong muốn, chính xác được tạo ra :

X

Khi được áp dụng trên tài liệu XML này :

<categoryName></categoryName>

hoặc về điều này:

<categoryName/>

hoặc về điều này

<somethingElse>Y</somethingElse>

kết quả chính xác được tạo ra :

Other

Tương tự, sử dụng phép chuyển đổi XSLT 1.0 này :

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

Lưu ý : Không có điều kiện được sử dụng ở tất cả. Tìm hiểu thêm về tầm quan trọng của việc tránh các cấu trúc có điều kiện trong khóa học Pluralsight tuyệt vời này:

" Các mẫu thiết kế chiến thuật trong .NET: Control Flow "


Xin chào Dimitre, tôi cần giải pháp của bạn cho 1.0, vì vậy tôi có cần mã hóa nó trong mọi thẻ mà tôi có hoặc có cách nào đơn giản hơn để áp đặt nó cho toàn bộ XML không?
zyberjock

@zyberjock, Không rõ bạn đang hỏi gì. Xin vui lòng, gửi một câu hỏi và gửi cho tôi một bình luận với một liên kết. Thực hiện theo các hướng dẫn làm thế nào để hỏi một câu hỏi hay.
Dimitre Novatchev

Xin chào @Dimitre, tôi đã đăng câu hỏi tại đây stackoverflow.com/questions/38150093/NH
zyberjock

4

Nếu có khả năng phần tử không tồn tại trong XML, tôi sẽ kiểm tra cả phần tử có mặt và độ dài chuỗi lớn hơn 0:

<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
Giá trị chuỗi của một tập hợp nút trống (là biểu thức XPath categoryNamecung cấp cho bạn khi không có categoryNamephần tử con nào trong ngữ cảnh hiện tại) được xác định là chuỗi trống, do đó, đây là dự phòng - string-length(categoryName)bằng 0 nếu không có categoryNamephần tử.
Ian Roberts

3

Nếu một nút không có giá trị khả dụng trong xml đầu vào như bên dưới xpath,

<node>
    <ErrorCode/>
</node>

Hàm chuỗi () chuyển thành giá trị trống. Vì vậy, điều này hoạt động tốt:

string(/Node/ErrorCode) =''

2

Một cái gì đó như thế này làm việc cho tôi:

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

Hoặc cách khác xung quanh:

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

Lưu ý: Nếu bạn không kiểm tra giá trị null hoặc xử lý giá trị null, IE7 trả về -2147483648 thay vì NaN.


1

Tôi thực sự thấy tốt hơn là chỉ kiểm tra độ dài chuỗi vì nhiều lần trường không rỗng, chỉ trống

<xsl: when test = "chuỗi độ dài (trường bạn muốn kiểm tra) <1">


0

Theo kinh nghiệm của tôi, cách tốt nhất là:

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

0

Sử dụng danh mục đơn giản / văn bản () Kiểm tra như vậy hoạt động tốt <categoryName/>và cũng <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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.