XSLT에서 문자열이 null인지 또는 비어 있는지 확인


325

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>

코드 예제를 확장 할 수 있습니까?
Nick Allen

유스 케이스에 따라 xsl:when노드 테스트 에 사용하지 않을 수도 있습니다. <xsl:template match="Category[categoryName[not(node())]]">...와 함께 고려하십시오 <xsl:template match="Category">.... 그러면 프로세서가 올바른 결정을 내릴 수 있으며 xsl:choose더 이상 중첩 된 비즈니스 로직을 작성할 필요가 없습니다. 대부분의 경우 일치하는 템플릿을 사용하면 스타일 시트를보다 쉽게 ​​작성할 수 있습니다.
Abel

답변:


322
test="categoryName != ''"

편집 : 이것은 의사 코드와 XSLT에 대한 내 자신의 초기 경험을 포함하여 질문에서 유추 한 "null 또는 empty가 아님"에 대한 가장 가능성있는 해석을 다룹니다. 즉, "다음 Java와 동등한 것은 무엇입니까?":

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

예를 들어 null과 빈을 명확하게 식별하는 자세한 내용은 아래의 johnvey의 답변 및 / 또는 해당 답변에서 수정 한 XSLT 'fiddle'을 참조하십시오 . 여기에는 Michael Kay의 의견에있는 옵션과 가능한 여섯 번째 해석이 포함됩니다.


14
이 테스트의 자세한 의미는 다음과 같습니다. 문자열 값이 빈 문자열 인 categoryName 요소가 하나 이상 있으면 true를 반환합니다.
jelovirt

14
@jelovirt 빈 문자열이 아닌 categoryName이 하나 이상 있는지 말하려고 했습니까? (I는 XSL 초보자, 그래서 내 질문에 대한 잠재적 인 어리 석음을 용서 해요.)
joedevon

10
이 답변은 많은 찬사를 받았지만 매우 오해의 소지가 있습니다. "널 또는 비어 있음"의 의미에 따라 다릅니다. categoryName이 없거나 길이가 0 인 값이있는 경우 성공하는 테스트를 원하면을 사용해야합니다 test="not(categoryName = '')". categoryName 요소가 없으면 제공된 답변이 false를 반환하므로 질문을 해석 할 때 잘못된 답변이됩니다.
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 등)에서 종료 태그는 별도의 엔티티로 간주되지 않습니다. 대신 시작 태그와 끝 태그 사이의 전체 인 노드 또는 요소 만 처리합니다. 간단히 말해서를 테스트 할 방법이 없으며 </CategoryName>필요하지도 않습니다.
Abel

4
나는이 답변에 대해 특별히 질문에 별표를 표시했으며, 질문은 꽤 오래되었지만이 답변은 선택된 답변이 될만한 가치가있는 것 같습니다
Patrick

68

에서 빈 요소 :

특정 노드의 값이 비어 있는지 테스트하려면

그것은 당신이 비어있는 의미에 달려 있습니다.

  • 자식 노드가 없습니다 : not(node())
  • 텍스트 내용이 없습니다 : not(string(.))
  • 공백 이외의 텍스트를 포함하지 않습니다. not(normalize-space(.))
  • 주석 외에는 아무것도 포함하지 않습니다 : not(node()[not(self::comment())])

2
+1. 몇 가지 메모. 첫 번째 글 머리 기호는 텍스트 내용 (노드이기도 함)도 테스트합니다. 두 번째 글 머리 기호는 모든 노드에서 깊이에 상관없이 텍스트 노드를 테스트합니다. 현재 노드에 텍스트가 없지만 다른 노드를 포함 할 수 있는지 알고 싶다면을 사용할 수 있습니다 not(text()). 두 번째 글 머리 기호에 대한 대안도 있습니다 not(.//text()). 마지막 글 머리표에서 알 수 있듯이 "무 (無)"를 고려하는 방법에는 여러 가지가 있습니다.;).
Abel

매우 실용적 : 문자열이 비어 있지 않은지 테스트하려면 문자열 자체 만 테스트하면됩니다! if ($mystring) then ... else ...
Felix Dombek

22

이건 어떤가요?

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

1
이것은 잘 작동합니다. 내부에 주석이 <categoryName> <!-- some comment --> </categoryName>있고 의미가없는 텍스트가없는 경우에도, 이것은 여전히 true
rustyx로

9

처음 두 개는 null 값을 처리하고 두 번째 두 개는 빈 문자열을 처리합니다.

<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

경우에 따라 값이 구체적으로 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>

널 요소에 대해서는 true를 리턴합니다.


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>

즉, 0, 비어 있거나 단일 또는 여러 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 버전에서) 작동합니다. "fall-through"일치 템플릿 인 두 번째 템플릿은 유효하지 않은 것을 포착합니다. 그런 다음 세 번째 categoryName는 올바른 방식으로 값 을 출력합니다 .

이 시나리오에서는 달리 명시하지 않는 한 프로세서가 모든 하위 항목을 자동으로 처리하기 때문에 categories또는이 항목을 명시 적으로 일치시킬 필요 category가 없습니다 xsl:apply-templates. 그들).

이 접근 방식은 여러 범주를 자동으로 처리하고 다른 일치하는 템플릿을 추가하여 다른 요소 또는 예외에 대해 확장 할 수 있기 때문에 명령 방식보다 확장 성이 뛰어납니다. if-branches가없는 프로그래밍 .

참고 : nullXML 과 같은 것은 없습니다 . 이 XSI : 전무는 하지만 거의 어떤 종류의 스키마없이 형식화되지 않은 상황에서, 특히 거의 사용되지 않는다.


1
" if-branches없는 프로그래밍 "을 언급 한 것을 축하합니다 . 이것의 중요성을 이해하지 못하는 사람들이 있습니다. 여기 모두 Zoran Horvat의 " .NET의 전술 디자인 패턴 : 제어 흐름 " 주제에 대한 매우 훌륭한 Pluralsight 과정의 링크입니다 . app.pluralsight.com/library/courses/… 반드시 읽어야합니다!
Dimitre Novatchev

5

XSL에서 값이 null인지 또는 비어 있는지 어떻게 확인할 수 있습니까?

예를 들어 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에 존재하지 않을 가능성이 있다면 요소가 존재하고 문자열 길이가 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
빈 노드 세트의 문자열 값 ( 현재 컨텍스트에 하위 요소 categoryName가 없을 때 XPath 표현식이 제공하는 것 categoryName)은 빈 문자열로 정의되므로 중복 string-length(categoryName)되지 않습니다 categoryName. 요소 가없는 경우 0 입니다.
Ian Roberts

3

아래의 xpath와 같이 입력 xml에서 노드에 사용 가능한 값이없는 경우,

<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은 NaN 대신 -2147483648을 반환합니다.


1

실제로 필드가 null이 아니고 비어있는 문자열 길이를 테스트하는 것이 더 좋습니다.

<xsl : when test = "string-length (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.