ตรวจสอบว่าสตริงเป็นโมฆะหรือว่างเปล่าใน XSLT


325

ฉันจะตรวจสอบว่าค่าเป็นโมฆะหรือว่างเปล่าด้วยXSL ได้อย่างไร

ตัวอย่างเช่นถ้า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>

คุณสามารถขยายตัวอย่างรหัสได้หรือไม่
Nick Allen

ขึ้นอยู่กับการใช้งานของคุณคุณอาจไม่ต้องการใช้xsl:whenสำหรับการทดสอบโหนด พิจารณาร่วมกับ<xsl:template match="Category[categoryName[not(node())]]">... <xsl:template match="Category">...ตัวประมวลผลจะทำการตัดสินใจที่ถูกต้องสำหรับคุณและคุณไม่จำเป็นต้องเขียนตรรกะทางธุรกิจในที่ซ้อนกันxsl:chooseอีกต่อไป ในหลายกรณีการใช้แม่แบบการจับคู่ทำให้การเขียนสไตล์เป็นเรื่องง่ายขึ้น
Abel

คำตอบ:


322
test="categoryName != ''"

แก้ไข : สิ่งนี้ครอบคลุมการตีความที่น่าจะเป็นไปได้มากที่สุดในความเห็นของฉันว่า "[ไม่] เป็นโมฆะหรือว่างเปล่า" ตามที่อนุมานจากคำถามรวมถึงรหัสหลอกและประสบการณ์เริ่มต้นของฉันกับ XSLT เช่น "Java เทียบเท่าต่อไปนี้คืออะไร":

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

สำหรับรายละเอียดเพิ่มเติมเช่นระบุค่าว่างเปล่ากับค่าว่างดูคำตอบของ johnvey ด้านล่างและ / หรือ'ซอ' ของ XSLT ที่ฉันดัดแปลงมาจากคำตอบนั้นซึ่งรวมถึงตัวเลือกในความคิดเห็นของ Michael Kay และการตีความที่เป็นไปได้ที่หก


14
ความหมายโดยละเอียดของการทดสอบนี้คือ: คืนค่าจริงหากมีอย่างน้อยหนึ่งองค์ประกอบ CategoryName ที่มีค่าสตริงเป็นสตริงว่าง
jelovirt

14
@jelovirt คุณหมายถึงว่าถ้ามีอย่างน้อยหนึ่งหมวดหมู่ที่ไม่ใช่สตริงว่างเปล่า? (ผมเป็นมือใหม่ XSL เพื่อยกโทษความโง่เขลาที่อาจเกิดขึ้นกับคำถามของฉัน.)
joedevon

10
คำตอบนี้ในขณะที่ได้รับการยอมรับและลงคะแนนสูงก็ทำให้เข้าใจผิดมาก มันขึ้นอยู่กับสิ่งที่คุณหมายถึงโดย "โมฆะหรือเปล่า" หากคุณต้องการการทดสอบที่ประสบความสำเร็จถ้า CategoryName test="not(categoryName = '')"เป็นทั้งขาดหรือปัจจุบันที่มีค่าเป็นศูนย์ที่มีความยาวคุณควรใช้ คำตอบที่ให้มาจะกลับเท็จถ้าองค์ประกอบ categoryName ขาดซึ่งในการตีความของฉันของคำถามทำให้มันเป็นคำตอบที่ผิด
Michael Kay

2
@MichaelKay: ฉันได้อัปเดตคำตอบเพื่อให้รายละเอียดเพิ่มเติม ขอบคุณสำหรับความคิดเห็นและโปรเซสเซอร์ Saxon XSLT!
steamer25

ฉันจะแปล<xsl:for-each select="root/*[matches(name(.), 'grp')]">เพื่อใช้ใน VS2010 ได้อย่างไร
Si8

276

หากไม่มีข้อมูลอื่น ๆ ฉันจะถือว่า 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>

คุณจะทดสอบอินสแตนซ์ของได้</CategoryName>อย่างไร การทดสอบสตริงที่ว่างเปล่าไม่สามารถใช้งานได้
raffian

3
ขอขอบคุณที่คุณรวมหลายตัวอย่างเพื่อแสดงให้เห็นว่าแต่ละผลลัพธ์ของนิพจน์
doubleJ

1
@raffian: ใน XSLT หรือเทคโนโลยีที่เกี่ยวข้อง (XQuery, DOM, XDM, Schema ฯลฯ ) แท็กสิ้นสุดจะไม่ถือว่าเป็นเอนทิตีที่แยกต่างหาก แต่คุณจะต้องจัดการกับโหนดหรือองค์ประกอบในกรณีนี้ซึ่งเป็นผลรวมระหว่าง start-tag และ end-tag ในระยะสั้นไม่มีวิธีการทดสอบ</CategoryName>และไม่จำเป็นต้องมี
Abel

4
ฉันติดดาวคำถามสำหรับคำตอบนี้โดยเฉพาะและในขณะที่คำถามนั้นค่อนข้างเก่า แต่คำถามนี้ดูเหมือนจะสมควรเป็นคำตอบที่เลือกแล้ว
Patrick

68

จากองค์ประกอบที่ว่างเปล่า :

เพื่อทดสอบว่าค่าของโหนดใดโหนดหนึ่งว่างเปล่า

ขึ้นอยู่กับว่าคุณหมายถึงอะไรว่าง

  • ไม่มีโหนดย่อย: not(node())
  • ไม่มีเนื้อหาข้อความ: not(string(.))
  • ไม่มีข้อความอื่นนอกจากช่องว่าง: not(normalize-space(.))
  • ไม่มีอะไรนอกจากความคิดเห็น: not(node()[not(self::comment())])

2
+1 บางบันทึก กระสุนแรกยังทดสอบเนื้อหาข้อความซึ่งเป็นโหนด bulletpoint สองทดสอบสำหรับโหนดข้อความใด ๆ ที่ระดับความลึกใด ๆ หากคุณต้องการที่จะรู้ว่าถ้าโหนดปัจจุบันไม่ได้มีข้อความ แต่สามารถมีโหนดอื่น ๆ not(text())คุณสามารถใช้ ทางเลือกในการกระสุนที่ 2 not(.//text())ของคุณนอกจากนี้ยังมี ตามที่แสดงหัวข้อย่อยล่าสุดของคุณ: มีหลายวิธีในการพิจารณา "nothingness";)
Abel

มีประโยชน์มาก: เพื่อทดสอบว่าสตริงไม่ว่างคุณสามารถทดสอบสตริงได้เอง! if ($mystring) then ... else ...
เฟลิกซ์ Dombek

22

เกี่ยวกับอะไร

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

1
มันใช้งานได้ดี แม้ว่าจะมีความคิดเห็นอยู่ภายใน<categoryName> <!-- some comment --> </categoryName>และไม่มีข้อความที่มีความหมาย แต่อย่างใดยังคงมีการประเมินถึงtrue
rustyx

9

สองข้อแรกมีค่าว่างและสองข้อสองกับสตริงว่าง

<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
น่ากลัว เกิดอะไรขึ้นถ้ามีผู้ใช้หลายคนหรือชื่อแรกหลายคน? ใช้xsl:apply-templatesและจับคู่แม่แบบเพื่อให้ได้สิ่งที่คุณต้องการง่ายกว่ามาก
Abel

7

ในบางกรณีคุณอาจต้องการทราบเมื่อค่าเป็นโมฆะเฉพาะซึ่งจำเป็นอย่างยิ่งเมื่อใช้ XML ซึ่งได้รับการต่อเนื่องจากวัตถุ. NET ในขณะที่คำตอบที่ได้รับการยอมรับใช้ได้ผลก็ยังส่งกลับผลลัพธ์เดียวกันเมื่อสตริงว่างหรือว่างเปล่าเช่น '' ดังนั้นคุณจึงไม่สามารถแยกความแตกต่างได้

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

ดังนั้นคุณสามารถทดสอบคุณสมบัติได้

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

บางครั้งจำเป็นต้องทราบสถานะที่แน่นอนและคุณไม่สามารถตรวจสอบได้ว่า CategoryName นั้นมีอินสแตนซ์หรือไม่เนื่องจากไม่เหมือนกับจาวาสคริปต์

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

จะส่งคืนจริงสำหรับองค์ประกอบที่เป็นโมฆะ


6

ฉันรู้ว่าคำถามนี้เก่า แต่ระหว่างคำตอบทั้งหมดฉันคิดถึงคำถามที่เป็นวิธีการทั่วไปสำหรับกรณีการใช้งานนี้ในการพัฒนา 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สร้างสไตล์หรือกล่าวอีกนัยหนึ่งคือยุ่งเหยิงอย่างรวดเร็ว (ยิ่งกว่านั้นหากองค์ประกอบสามารถอยู่ในระดับที่แตกต่างกัน!) สำนวนการเขียนโปรแกรมทั่วไปใน XSLT กำลังใช้เท็มเพลต (ดังนั้น T ใน XSLT) ซึ่งเป็นการเขียนโปรแกรมแบบประกาศไม่จำเป็น (คุณไม่ได้บอกหน่วยประมวลผลว่าจะทำอย่างไรคุณเพียงแค่บอกสิ่งที่คุณต้องการเอาท์พุท สำหรับกรณีการใช้งานนี้สามารถมีลักษณะดังนี้:

<!-- 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 ใด ๆ ) เพราะอันแรกเหนือมีความสำคัญมากกว่า (มันมีภาคแสดง) เทมเพลตการจับคู่ "แบบหล่นทะลุ" อันที่สองจะจับอะไรที่ไม่ถูกต้อง อันที่สามจะดูแลการส่งออกcategoryNameค่าในวิธีที่เหมาะสม

โปรดทราบว่าในสถานการณ์นี้มีความจำเป็นต้อง specifially ตรงกับไม่มีcategoriesหรือcategoryเพราะการประมวลผลจะดำเนินการเด็กทุกคนโดยอัตโนมัติจนกว่าเราจะบอกได้ว่ามันเป็นอย่างอื่น (ในตัวอย่างนี้ที่สองและแม่แบบที่สามทำกระบวนการไม่ได้ต่อเด็กเพราะไม่มีxsl:apply-templatesใน พวกเขา)

วิธีการนี้สามารถขยายได้ง่ายขึ้นจากนั้นจึงเป็นวิธีการที่จำเป็นเนื่องจากจะเกี่ยวข้องกับหลายหมวดหมู่โดยอัตโนมัติและสามารถขยายได้สำหรับองค์ประกอบหรือข้อยกเว้นอื่น ๆ โดยเพียงเพิ่มแม่แบบการจับคู่อื่น โดยไม่ต้องเขียนโปรแกรมถ้าสาขา

หมายเหตุ: ไม่มีสิ่งเช่นnullใน XML มีxsi: nilแต่ไม่ค่อยมีใครใช้โดยเฉพาะอย่างยิ่งในสถานการณ์ที่ไม่ได้พิมพ์โดยไม่มี schema บางประเภท


1
ยินดีด้วยกับการกล่าวถึง " การเขียนโปรแกรมโดยไม่มี if-branch " มีบางคนที่ไม่เข้าใจความสำคัญของสิ่งนี้ สำหรับพวกเขาทั้งหมดที่นี่เป็นลิงค์ไปยังหลักสูตร Pluralsight ที่ดีมากในหัวข้อนี้: " รูปแบบการออกแบบเกี่ยวกับยุทธวิธีใน. NET: Control Flow " โดย Zoran Horvat: app.pluralsight.com/library/courses/c ต้องอ่าน!
Dimitre Novatchev

5

ฉันจะตรวจสอบว่าค่าเป็นโมฆะหรือว่างเปล่าด้วย XSL ได้อย่างไร

ตัวอย่างเช่นถ้าcategoryNameว่างเปล่า

นี่อาจเป็นนิพจน์ XPath ที่ง่ายที่สุด (คำตอบที่ยอมรับได้นั้นให้การทดสอบแบบตรงกันข้าม

not(string(categoryName))

คำอธิบาย :

อาร์กิวเมนต์ของnot()ฟังก์ชั่นด้านบนเป็นสิ่งที่ถูกfalse()ต้องเมื่อไม่มีรายการย่อยcategoryName("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>

ใน 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 ที่ดีนี้:

" รูปแบบการออกแบบเกี่ยวกับยุทธวิธีใน. NET: การควบคุมการไหล "


สวัสดี Dimitre ฉันต้องการโซลูชันของคุณสำหรับ 1.0 ดังนั้นฉันจำเป็นต้องเขียนโค้ดในทุกแท็กที่ฉันมีหรือมีวิธีที่ง่ายกว่าในการใช้สำหรับ XML ทั้งหมดหรือไม่
zyberjock

@zyberjock มันไม่ชัดเจนในสิ่งที่คุณถาม กรุณาโพสต์คำถามและส่งความคิดเห็นพร้อมลิงค์ ทำตามคำแนะนำวิธีการถามคำถามที่ดี
Dimitre Novatchev

สวัสดี @Dimitre ฉันโพสต์คำถามได้ที่นี่stackoverflow.com/questions/38150093/ …
zyberjock

4

หากมีความเป็นไปได้ที่องค์ประกอบนั้นไม่มีอยู่ใน XML ฉันจะทดสอบว่าองค์ประกอบนั้นมีอยู่และความยาวของสตริงนั้นมากกว่าศูนย์:

<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
ค่าสตริงของชุดโหนดว่าง (ซึ่งเป็นสิ่งที่นิพจน์ XPath categoryNameให้คุณเมื่อไม่มีcategoryNameองค์ประกอบย่อยในบริบทปัจจุบัน) ถูกกำหนดให้เป็นสตริงว่างดังนั้นนี่จึงซ้ำซ้อน - string-length(categoryName)เป็นศูนย์ถ้าไม่มีcategoryNameองค์ประกอบ
Ian Roberts

3

หากโหนดไม่มีค่าในอินพุต xml เช่นด้านล่าง xpath

<node>
    <ErrorCode/>
</node>

ฟังก์ชัน string () แปลงเป็นค่าว่าง ดังนั้นจึงใช้งานได้ดี:

string(/Node/ErrorCode) =''

2

สิ่งนี้เหมาะกับฉัน:

<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 จะคืนค่า -2147483648 แทน NaN


1

ฉันพบว่ามันดีกว่าแค่ทดสอบความยาวสตริงเนื่องจากหลายครั้งที่ฟิลด์ไม่ว่างเปล่า

<xsl: when test = "ความยาวสตริง (field-you-want-to-test) <1">


0

จากประสบการณ์ของฉันวิธีที่ดีที่สุดคือ:

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

0

ใช้ CategoryName / ข้อความง่าย () การทดสอบดังกล่าวทำงานได้ดีบนและ<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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.