2016-09-08 5 views
8

현재 다양한 버전의 Saxon-Processor를 사용하는 순수 XSL 변환 작업을하고 있습니다.XSLT 함수가 다른 결과를 반환합니다 [Saxon-EE Saxon-HE/PE]

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:foo="bar"> 

    <xsl:output encoding="UTF-8" method="text"/> 

    <xsl:template match="/"> 
     <xsl:text>Call of func_1: </xsl:text>   
     <xsl:value-of select="foo:func_1()"/> 

     <xsl:text>&#xA;Call of func_1: </xsl:text> 
     <xsl:value-of select="foo:func_1()"/> 

     <xsl:text>&#xA;Call of func_1: </xsl:text> 
     <xsl:value-of select="foo:func_1()"/> 

     <xsl:text>&#xA;Call of func_2: </xsl:text> 
     <xsl:value-of select="foo:func_2()"/> 
    </xsl:template> 

    <xsl:function name="foo:func_1" as="xs:string"> 
     <!-- do some other stuff --> 
     <xsl:value-of select="foo:func_2()"/> 
    </xsl:function> 

    <xsl:function name="foo:func_2" as="xs:string"> 
     <xsl:variable name="node"> 
      <xsl:comment/> 
     </xsl:variable> 
     <xsl:sequence select="generate-id($node)"/> 
    </xsl:function> 

</xsl:stylesheet> 

설명

foo:func_1 무시 될 수있는 두 번째 함수 + 다른 물건을 값을 반환하는 래퍼 함수가된다 아래는 내 질문의 요구에 대한 단순화 된 나의 짧은 스타일이며, . 함수의이 개념은 다른 함수를 호출하는 것이 필수입니다!

foo:func_2은 요소에 대해 고유 한 ID를 생성합니다. 이 요소는 "node"라는 로컬 범위 변수에 작성됩니다. 색슨 버전을 기반으로

다른 결과

예상 된 결과 :

Call of func_1: d2 
Call of func_1: d3 
Call of func_1: d4 
Call of func_2: d5 

색슨-EE 9.6.0.7/색슨-EE 9.6.0.5 결과

Call of func_1: d2 
Call of func_1: d2 
Call of func_1: d2 
Call of func_2: d3 

색슨 -HE 9.6.0.5/삭스 에-PE 9.6.0.5/색슨-EE는 9.5.1.6/색슨-HE가 발생할 9.5.1.6

like expected 

또한 깊이

에 내가 늘어나는만큼 내 자신의 문제를 디버깅/질문 나는 할 수 있었다. 함수 "func_1"의 xsl:value-ofxsl:sequence으로 변경하면 [예기치 않은] 모든 버전에서 결과가 동일하게됩니다. 하지만 그건 내 의도가 아니야!

색슨 버전에서 xsl:value-ofxsl:sequence의 차이점은 무엇입니까? "숨겨진"캐싱이 있습니까? 필자의 경우 xsl:sequencexsl:value-of으로 작업하는 올바른 방법은 무엇입니까? [btw : 나는 이미 알고있다. value-of은 select-statement 결과로 텍스트 노드를 만든다. 시퀀스는 노드 또는 원자 값에 대한 참조가 될 수 있습니다. 내 문제를 afaik 해결하지 마십시오]

+1

흥미로운 문제입니다. 하지만 왜'as = "xs : string"'을 사용하여 문자열을 반환하는 것으로 선언 된 함수를 작성하는지 이해하지 못합니다. 그런 다음 텍스트 노드를 반환하는'xsl : value-of'를 사용합니다 (문자열을 캐스팅해야 함). 'as' 선언과 일치시킵니다). –

+1

Saxon 9.7 EE에서 명령 행에서'opt : 0'을 사용하여 최적화를 끄면 결과는 각 호출마다 다른 id가됩니다. 따라서 EE가 결과를 변경하는 최적화를 수행하고있는 것으로 보입니다. –

+1

XSLT 3.0은'new-each-time' 속성으로 https://www.w3.org/TR/xslt-30/#function-determinism의 문제를 해결하려고합니다. –

답변

2

이 오랜 문제와 오히려 깊은 문제입니다. 순수 함수 언어에서 동일한 인수로 순수 함수를 두 번 호출하면 항상 동일한 결과가 산출됩니다. 이것은 많은 최적화를 가능하게합니다. 예를 들어 인수가 불변 인 경우 함수 호출을 루프에서 꺼내거나 재귀가 아닌 경우 함수 호출을 인라이닝하는 것입니다. 불행히도 XSLT와 XQuery 함수는 완전히 순전히 기능적이지 않습니다. 특히 함수가 새 노드를 만드는 경우 함수를 두 번 호출하면 다른 노드가 생성됩니다 (f() is f()false을 반환합니다).

Saxon Optimizer는 이러한 제약 조건에서 가능한 한 최적화를 시도합니다. 특히 새 노드를 만드는 함수를 인식하고 이러한 함수를 적극적으로 최적화하지 않아야합니다.

하지만 사양 자체는 100 % 규정되어 있지 않습니다.예를 들어, 당신의 예제에서 함수 인자에 의존하지 않는 지역 변수가 있다면, 스펙은 변수의 값이 각 평가에서 같은 노드인지 또는 새로운 노드인지에 대한 구현에 라이센스를 부여한다고 생각합니다 .

새로운 XSLT 3.0 특성 new-each-time은이 기능을 제어하려고 시도합니다. 함수를 호출 할 때마다 실제로 새 노드를 원하면 new-each-time="yes"을 지정해야합니다.

참고 : 여기에 무슨 일이 일어나고 특정 최적화 (당신이 -explain 옵션을 실행하여 볼 수있는) 그 func_2 먼저 인라인 된 다음 그 몸은 전역 변수로 추출되고

. 일부 릴리스에서는이 작업을 수행하고 있으며 다른 작업은 수행하지 않습니다. 사소한 변경에 매우 민감 할 수 있습니다. 가장 좋은 충고는 이러한 종류의 부작용이있는 기능에 의존해서는 안됩니다. 실제 문제를 설명하면 도움이 될 것입니다. 그러면 어쩌면 언어 의미론에서 가장자리 사례에 너무 민감하지 않은 접근 방식을 찾을 수 있습니다.

+0

많은 의견을 보내 주셔서 감사합니다. 나는 이미 프로세서 최적화, 힌트 캐싱에 대해 생각했다. – uL1

+0

제 실제 시나리오 : 저는 널리 확산 된 uuid.xsl (소스가없고, 알려진 크레딧이 없습니다)을 사용하여 xslt에서 uuids를 생성합니다. 과거에는 내가 어떤 자바 클래스도 사용할 수 없기 때문에 xsl을 사용했다. 지금은 , 난'의 xmlns를 사용 UUID를 = "자바 : java.util.UUID' => 'UUID : randomUUID 하지만 그것이 나에게 중요했다가, 어쩌면 다시 직면하고있는 문제를 이해하기 위해()' 미래. 아직 실제 시나리오로 새 스레드를 열어야합니까? 가치가 있습니까? 그렇지 않으면 소중한 시간을 절약 할 수 있습니다. – uL1