2016-09-08 32 views
8

Tôi hiện đang làm việc trên một bộ chuyển đổi XSL thuần túy với Bộ xử lý Saxon trong các phiên bản khác nhau. Dưới đây là stylesheet ngắn của tôi, đơn giản hóa cho nhu cầu của câu hỏi của tôi:Chức năng XSLT trả về các kết quả khác nhau [Saxon-EE vs 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> 

Mô tả

foo:func_1 là một hàm wrapper để trả về giá trị của một hàm thứ hai + làm công cụ khác, có thể được bỏ qua . khái niệm hàm này gọi hàm khác là bắt buộc!

foo:func_2 tạo id duy nhất cho một phần tử. Phần tử này được tạo ra trong một biến phạm vi cục bộ có tên là "nút".

kết quả

khác nhau dựa trên các phiên bản Saxon

kết quả mong đợi:

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

Saxon-EE 9.6.0.7/Saxon-EE 9.6.0.5 Kết quả

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

Saxon-HE 9.6.0.5/Sax on-PE 9.6.0.5/Saxon-EE 9.5.1.6/Saxon-HE 9.5.1.6 dẫn

like expected 

Câu hỏi/hơn nữa trong sâu

tôi sửa lỗi các vấn đề trên của riêng tôi như xa như tôi có thể. NẾU tôi sẽ thay đổi xsl:value-of trong hàm "func_1" thành xsl:sequence, kết quả sẽ giống nhau đối với tất cả các phiên bản [như mong đợi]. Nhưng đó không phải là ý định của tôi!

Tôi muốn hiểu sự khác biệt giữa xsl:value-ofxsl:sequence trong suốt các phiên bản Saxon là gì. Có bộ nhớ đệm "ẩn" nào không? Cách chính xác để làm việc với xsl:sequencexsl:value-of trong trường hợp của tôi là gì. [btw: tôi biết rồi, giá trị tạo ra một nút văn bản với kết quả của câu lệnh chọn. chuỗi có thể là tham chiếu đến nút hoặc giá trị nguyên tử. đừng giải quyết vấn đề của tôi afaik]

+1

Sự cố thú vị. Nhưng tôi không hiểu tại sao bạn viết các hàm được khai báo là trả về một chuỗi với 'as =" xs: string "', sau đó sử dụng 'xsl: value-of' trả về một nút văn bản (mà sau đó phải được đúc thành chuỗi để khớp với khai báo 'as'). –

+1

Với Saxon 9.7 EE, nếu tôi tắt bất kỳ tối ưu hóa nào bằng cách sử dụng 'opt: 0' từ dòng lệnh, thì kết quả là một id khác nhau cho mỗi cuộc gọi. Vì vậy, có vẻ như EE đang thực hiện một số tối ưu hóa để thay đổi kết quả. –

+1

Tôi nghĩ XSLT 3.0 cố gắng giải quyết vấn đề trong https://www.w3.org/TR/xslt-30/#function-determinism với thuộc tính 'new-each-time'. –

Trả lời

2

Đây là vấn đề lâu dài và khá sâu. Trong một ngôn ngữ chức năng thuần túy, gọi một hàm thuần túy hai lần với các đối số giống nhau luôn tạo ra cùng một kết quả. Điều này làm cho nhiều tối ưu hóa có thể, chẳng hạn như kéo một cuộc gọi chức năng ra khỏi vòng lặp nếu các đối số là bất biến, hoặc nội tuyến một cuộc gọi hàm nếu nó không đệ quy. Thật không may là các hàm XSLT và XQuery không hoàn toàn là chức năng: đặc biệt, chúng được định nghĩa sao cho nếu hàm tạo các nút mới, sau đó gọi hàm hai lần tạo ra các nút khác nhau (f() is f() trả về false).

Trình tối ưu hóa Saxon cố gắng hết sức để tối ưu hóa trong phạm vi các ràng buộc này, đặc biệt bằng cách nhận biết các hàm tạo nút mới và tránh tối ưu hóa tích cực các chức năng như vậy.

Nhưng bản thân thông số kỹ thuật không phải là 100% quy định.Ví dụ, nếu như trong ví dụ của bạn có một biến cục bộ không phụ thuộc vào các đối số hàm, tôi nghĩ rằng spec cung cấp giấy phép cho việc thực hiện xem liệu giá trị của biến có phải là cùng một nút trên mỗi đánh giá hay không. .

Như Martin nói, thuộc tính XSLT 3.0 mới mỗi lần là một nỗ lực để kiểm soát điều này: nếu bạn thực sự muốn một nút mới mỗi lần hàm được gọi, bạn nên chỉ định new-each-time="yes".

Lưu ý:

Việc tối ưu hóa cụ thể mà đang xảy ra ở đây (mà bạn có thể nhìn thấy bằng cách chạy với tùy chọn -explain) được func_2 đó là lần đầu tiên sắp xếp theo hàng và sau đó cơ thể của nó được tách ra thành một biến toàn cầu . Một số bản phát hành đang làm điều này và một số khác thì không - nó có thể rất nhạy cảm với những thay đổi nhỏ. Lời khuyên tốt nhất là không phụ thuộc vào các chức năng có loại tác dụng phụ này. Nó sẽ giúp ích nếu bạn giải thích vấn đề thực sự của bạn, sau đó có lẽ chúng ta có thể tìm thấy một cách tiếp cận mà không phải là quá nhạy cảm với các trường hợp cạnh trong ngữ nghĩa ngôn ngữ.

+0

cảm ơn bạn rất nhiều vì đã có cái nhìn sâu sắc. tôi đã nghĩ về một số tối ưu hóa bộ xử lý, gợi ý bộ nhớ đệm. – uL1

+0

kịch bản thực của tôi: tôi đang sử dụng uuid.xsl được lan rộng rộng rãi (không có nguồn, không có tín dụng nào được biết) để tạo uuids trong xslt; trong quá khứ tôi không thể sử dụng bất kỳ lớp học java vì vậy tôi đã sử dụng xsl đó. cho bây giờ, tôi sử dụng 'xmlns: uuid =" java: java.util.UUID' => 'uuid: randomUUID()' NHƯNG nó quan trọng với tôi là, để hiểu được vấn đề có thể phải đối mặt với một lần nữa trong Tôi vẫn nên mở một chủ đề mới với kịch bản thực sự? giá trị nó? nếu không tôi tiết kiệm thời gian quý báu của bạn. – uL1

Các vấn đề liên quan