2009-05-07 4 views
26

노드 수를 계속 유지하려는 XML 파일을 처리 중이므로 새 노드를 쓸 때 ID로 사용할 수 있습니다.XSLT에서 전역 변수를 다른 범위에서 어떻게 증가시킬 수 있습니까?

현재 '카운터'라는 전역 변수가 있습니다. 템플릿 내에서 액세스 할 수 있지만 템플릿 내에서이를 조작하는 방법을 찾지 못했습니다.

<xsl:variable name="counter" select="1" as="xs:integer"/> 

<xsl:template match="/"> 
    <xsl:for-each select="section"> 
     <xsl:call-template name="section"></xsl:call-template> 
    </xsl:for-each> 
</xsl:template> 

<xsl:template name="section"> 

    <!-- Increment 'counter' here --> 

    <span class="title" id="title-{$counter}"><xsl:value-of select="title"/></span> 
</xsl:template> 

어떤 제안이 어떻게 여기에서 갈 : 여기

내 XSLT 파일의 압축 된 버전입니다?

답변

44

기타 -처럼 (XSLT에는 할당 문이 없음을 순전히 기능적인 프로그래밍 언어).

나는 지금까지 제안 된 해결책에 대한 대안이 있습니다. 매개 변수 전달을 피할 수 있습니다 (이는 XSLT에서 장황하고 추악합니다 - 심지어 그것을 인정할 것입니다).

<xsl:template name="section"> 
    <span class="title" id="title-{1 + count(preceding-sibling::section)}"> 
    <xsl:value-of select="title"/> 
    </span> 
</xsl:template> 

(참고 : 공백 코드 포맷으로, 당신의 결과에 나타나지 않습니다 공백 전용 텍스트 노드

의 XPath에서

, 당신은 단순히 선행 <section> 요소의 수를 현재의 셀 수

(position()을 사용하는 것과는 대조적으로)이 접근법의 큰 장점 중 하나는 스타일 시트가 현재 스타일 시트에만 의존한다는 것입니다. 현재 노드 목록에서. 처리를 변경 한 경우 (예 : <xsl:for-each>도 섹션뿐만 아니라 다른 요소도 처리되므로) position()의 값은 더 이상 문서의 <section> 요소의 위치와 반드시 일치하지 않습니다. 반면에 위와 같이 count()을 사용하면 각 <section> 요소의 위치와 항상 일치합니다. 이 방법은 코드의 다른 부분과의 연결을 줄이는 데 일반적으로 매우 좋은 방법입니다.

count() 대신 <xsl:number> 명령어를 사용할 수 있습니다. 여전히를 사용하려는 경우 (추가 변수 선언을 요구하는

<xsl:template name="section"> 
    <xsl:variable name="count"> 
    <xsl:number/> 
    </xsl:variable> 
    <span class="title" id="title-{$count}"> 
    <xsl:value-of select="title"/> 
    </span> 
</xsl:template> 

그것은 상세에 트레이드 오프가 : 그것은 기본 동작은 당신이 원하는 될 일이 같은 수준에서 모두 같은 이름의 요소 번호를 것입니다 속성 값 템플릿 중괄호), XPath 표현식을 대폭 간소화하므로 약간만 그렇습니다.

개선의 여지가 더 많습니다. 현재 노드 목록에 대한 종속성은 제거했지만 현재 노드에 종속되어 있습니다. 그 자체로는 나쁜 것이 아니지만 현재 노드가 무엇인지 템플릿을 보면 즉시 명확하지 않습니다. 템플릿의 이름이 "section"입니다. 처리중인 내용을 확실히 알기 위해 코드의 다른 부분을 살펴 봐야합니다. 그러나 그럴 필요는 없습니다.

예를 들어 <xsl:for-each><xsl:call-template>을 함께 사용하게 되었다면, 뒤로 물러서서 <xsl:apply-templates>을 사용하는 방법을 알아보세요.

<xsl:template match="/doc"> 
    <xsl:apply-templates select="section"/> 
</xsl:template> 

<xsl:template match="section"> 
    <xsl:variable name="count"> 
    <xsl:number/> 
    </xsl:variable> 
    <span class="title" id="title-{$count}"> 
    <xsl:value-of select="title"/> 
    </span> 
</xsl:template> 

뿐만 아니라 덜 상세이 방법 (<xsl:apply-templates/> 모두 <xsl:for-each><xsl:call-template/> 대체), 그러나 또한 현재 노드가 무엇 즉시 분명해진다. match 속성을 살펴 보는 것만으로도 <section> 요소를 처리하고 있음을 알고 즉시 <section> 요소를 계산하면됩니다.

match 속성을 갖는 템플릿 규칙 (예 : <xsl:template> 요소)의 작동 원리에 대한 간략한 설명은 "How XSLT Works"을 참조하십시오.

+0

정말 고마워요! 이 게시물 및 답변은 ​​매우 도움이되었습니다 – anpatel

+0

당신을 환영합니다! 다행이라고 생각하면 다행입니다. –

+0

죄송합니다, Evan,하지만 이것은 매우 비효율적 인 솔루션입니다 (O (N^2)). 매개 변수 전달을 사용하는 솔루션은 O (N) 만 가능합니다. "자세한 정보"에 대한이 모든 이야기는 바로이 것입니다 - 자세한 정보 및 효율성에 대한 언급이 없습니다. 제안 된 솔루션의 복잡성에 대해 언급하고 다른 가능한 솔루션과 비교하면이 대답을 독자에게 더욱 유용하게 활용할 수 있습니다. 이러한 이유로 나는이 답변을 조명 튜토리얼 유형으로 간주하고 제작 작업에는 실용적이지 않습니다. –

2

변수는 로컬 범위이며 xslt에서만 읽을 수 있습니다.

+0

를 링크에 대한 클래스를 생성합니다.내가 한 일을 성취하기 위해 취할 수있는 접근법을 알고 있습니까? – Marcel

+0

먼저 foreach 구문과 call-template을 사용하지 말아야한다고 말합니다. 이것은 절차 적 명령문이며 XSLT는 재귀 적입니다. 그러므로 절차 적이 아니라 재귀 적으로 생각해야합니다. @Bewarned 사용자가 보여주는 것은 매개 변수를 통해 카운터를 증가시키는 유효한 방법입니다. 그런 다음 매번 1을 더하는 매개 변수와 함께 apply-template을 더 잘 사용하십시오. 내가 명확하지 않은 경우 그냥 주석으로 처리하십시오. – Luixv

8

XSLT 변수는 변경할 수 없습니다. 템플리트에서 템플리트로 값을 전달해야합니다.

XSLT 2.0을 사용하는 경우 매개 변수를 가질 수 있으며 터널링을 사용하여 변수를 올바른 템플릿에 전파 할 수 있습니다.

<xsl:template match="a"> 
<xsl:param name="count" select="0"> 
    <xsl:apply-templates> 
    <xsl:with-param select="$count+1"/> 
    </xsl:apply-templates> 
</xsl:template> 

은 또한()는 ID를 만들려면 생성-ID를 사용하여 볼 :

템플릿이 다음과 같이 보일 것입니다.

+2

+1 for generate-id() 감사합니다! –

0

본인이 직접 시도하지 않았지만 매개 변수를 템플릿에 전달할 수 있습니다. 첫 번째 템플릿에서 for-each 문 내에서 매개 변수를 count() (또는 current()일까요?)로 설정 한 다음 해당 값을 "섹션"템플릿에 전달합니다.

여기에 더 passing parameters to templates

2

당신의 XSLT 프로세서에 따라에, 당신은 당신의 XLST에 스크립트 기능을 소개 할 수 있습니다입니다. 예를 들어 Microsoft XML 라이브러리는 javascript를 지원합니다. 예를 들어 http://msdn.microsoft.com/en-us/library/aa970889(VS.85).aspx을 참조하십시오. 이 방법은 공개 클라이언트 브라우저에 XSLT를 배포/실행하려는 경우 분명히 작동하지 않습니다. 특정 XSLT 프로세서에서 수행해야합니다.

+0

이전에는 그 트릭을 사용해 보았습니다 만, 최후의 수단으로 만해야합니다. 변경 불가능한/기능적 라인을 따라 구조화하는 것이 금지됩니다. 그러나 그것은 효과적이다. 일부 시나리오 (예 : .NET)에서는 확장 개체를 사용하여 xslt 외부에서 동일한 작업을 수행 할 수 있지만 다시 말하면 좋은 생각이 아닙니다. –

1

position() 함수를 사용하여 원하는 것을 할 수 있습니다. 이런 식으로 보일 겁니다.

<xsl:template match="/"> 
    <xsl:for-each select="section"> 
    <xsl:call-template name="section"> 
     <xsl:with-param name="counter" select="{position()}"/> 
    </xsl:call-template> 
    </xsl:for-each> 
</xsl:template> 

<xsl:template name="section"> 
    <xsl:param name="counter"/> 
    <span class="title" id="title-{$counter}"> 
    <xsl:value-of select="title"/> 
    </span> 
</xsl:template> 
+0

xsl : with-param의 select 속성은 AVT를 사용할 수있는 String이 아닌 Expression입니다. – jelovirt

+0

또한 은 현재 노드 목록을 변경하지 않기 때문에 position() 값을 전달할 필요가 없습니다. "섹션"템플릿 내에서 position()을 사용하여 동일한 값에 쉽게 액세스 할 수 있습니다. –

6

XSLT의 변수는 불변하므로이를 염두에 두어야합니다. 당신은 직접 position()을 사용할 수

<xsl:template match="/"> 
    <xsl:for-each select="section"> 
     <xsl:call-template name="section"/> 
    </xsl:for-each> 
</xsl:template> 

<xsl:template name="section"> 
    <span class="title" id="title-{position()}"><xsl:value-of select="title"/></span> 
</xsl:template> 

또는 더 템플릿 지향 방법으로

:

<xsl:template match="/"> 
    <xsl:apply-templates select="section"/> 
</xsl:template> 

<xsl:template match="section"> 
    <span class="title" id="title-{position()}"><xsl:value-of select="title"/></span> 
</xsl:template> 
이미 변수는 불변하는 방법을 설명했다
0

증분 값으로 사용 <xsl:variable name="RowNum" select="count(./preceding-sibling::*)" />$ ROWNUM.

예는 : <xsl:template name="ME-homeTiles" match="Row[@Style='ME-homeTiles']" mode="itemstyle"> <xsl:variable name="RowNum" select="count(./preceding-sibling::*)" /> ...<a href="{$SafeLinkUrl}" class="tile{$RowNum}"><img ....></a>

이 ... 값 타일 1, tile2, tile3 등으로 내가 볼

관련 문제