Những người khác đã giải thích như thế nào biến là không thay đổi - rằng không có câu lệnh gán trong XSLT (như với ngôn ngữ lập trình hoàn toàn chức năng nói chung).
Tôi có một giải pháp thay thế cho các giải pháp đã được đề xuất cho đến thời điểm này. Nó tránh đi qua tham số (nó dài dòng và xấu xí trong XSLT - thậm chí tôi sẽ thừa nhận điều đó).
Trong XPath, bạn chỉ có thể đếm số <section>
yếu tố mà trước hiện thời:
<xsl:template name="section">
<span class="title" id="title-{1 + count(preceding-sibling::section)}">
<xsl:value-of select="title"/>
</span>
</xsl:template>
(Lưu ý: mã định dạng khoảng trắng sẽ không xuất hiện trong kết quả của bạn, như khoảng trắng chỉ các nút văn bản Vì vậy, đừng cảm thấy bị ép buộc phải đặt các chỉ dẫn trên cùng một dòng.)
Một lợi thế lớn của phương pháp này (trái ngược với việc sử dụng position()
) là nó chỉ phụ thuộc vào nút hiện tại, chứ không phải trên danh sách nút hiện tại. Nếu bạn đã thay đổi cách xử lý của mình bằng cách nào đó (ví dụ: do đó, <xsl:for-each>
không chỉ xử lý các phần mà còn một số phần tử khác), thì giá trị của position()
sẽ không còn tương ứng với vị trí của các yếu tố <section>
trong tài liệu của bạn. Mặt khác, nếu bạn sử dụng count()
như trên, thì nó sẽ luôn tương ứng với vị trí của mỗi phần tử <section>
. Cách tiếp cận này làm giảm sự ghép nối với các phần khác của mã của bạn, mà nói chung là một điều rất tốt.
Cách thay thế để đếm() sẽ là sử dụng hướng dẫn <xsl:number>
. Đó là hành vi mặc định sẽ đánh số tất cả các yếu tố như tên cùng cấp, mà sẽ xảy ra là những gì bạn muốn:
<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>
Đó là một sự đánh đổi trong tính cách rườm rà (đòi hỏi một khai báo biến bổ sung nếu bạn vẫn muốn sử dụng giá trị thuộc tính của các mẫu dấu ngoặc nhọn), nhưng chỉ một chút, vì nó cũng đơn giản hóa đáng kể biểu thức XPath của bạn.
Vẫn còn nhiều chỗ để cải thiện. Mặc dù chúng tôi đã xóa phụ thuộc vào danh sách nút hiện tại nhưng chúng tôi vẫn phụ thuộc vào nút hiện tại. Điều đó, trong và của chính nó, không phải là một điều xấu, nhưng nó không phải ngay lập tức rõ ràng từ nhìn vào mẫu những gì các nút hiện tại là. Tất cả những gì chúng ta biết là mẫu được đặt tên là "section
"; để biết chắc chắn những gì đang được xử lý, chúng ta phải tìm nơi khác trong mã của chúng tôi. Nhưng ngay cả điều đó không phải là trường hợp.
Nếu bạn cảm thấy đã dẫn đến sử dụng <xsl:for-each>
và <xsl:call-template>
cùng nhau (như trong ví dụ của bạn), hãy quay lại và tìm hiểu cách sử dụng <xsl:apply-templates>
thay thế.
<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>
Không chỉ là phương pháp này ít tiết (<xsl:apply-templates/>
thay thế cả hai <xsl:for-each>
và <xsl:call-template/>
), nhưng nó cũng trở nên ngay lập tức rõ ràng những gì nút hiện tại là. Tất cả những gì bạn phải làm là nhìn vào thuộc tính match
và bạn ngay lập tức biết rằng bạn đang xử lý một phần tử <section>
và các thành phần <section>
là những gì bạn đang đếm.
Để có giải thích ngắn gọn về cách các quy tắc mẫu (tức là <xsl:template>
các phần tử có thuộc tính match
) hoạt động, hãy xem "How XSLT Works".
Cảm ơn bạn rất nhiều !! Bài đăng và câu trả lời này cực kỳ hữu ích – anpatel
Bạn được chào đón! Thật vui khi bạn thấy nó hữu ích. –
Xin lỗi, Evan, nhưng đây là một giải pháp rất kém hiệu quả (O (N^2)). Một giải pháp sử dụng tham số truyền qua có thể là O (N). Tất cả điều này nói về "verbosity" chỉ là này - verbosity và không đề cập đến một từ về hiệu quả. Bạn có thể làm cho câu trả lời này hữu ích hơn cho người đọc nếu bạn đề cập đến độ phức tạp của giải pháp được đề xuất và so sánh nó với các giải pháp có thể khác. Vì những lý do này, tôi coi câu trả lời này là loại hướng dẫn ánh sáng và không thực tế cho công việc sản xuất. –