2012-01-31 69 views
7

Tôi có một chuỗi trong một tập tin XML trông tương tự như sau:Bắt một chuỗi SAU xuất hiện cuối cùng của một nhân vật trong XSLT

M: Namespace.Class.Method (Một cái gì đó một cái gì đó b)

Số ký tự dấu chấm (.) Là tùy ý, có nghĩa là nó chỉ có thể là 2 như trong ví dụ này, nhưng có thể nhiều hơn.

Tôi muốn sử dụng XSLT để nhận chuỗi con của chuỗi này từ '.' nhân vật, vì vậy mà tôi sẽ chỉ được trái với:

Method (Một cái gì đó một cái gì đó b)

tôi không thể đạt được điều này bằng cách sử dụng chuỗi tiêu chuẩn/substring-sau khi chức năng.

Có cách nào dễ dàng để thực hiện việc này không?

+0

Ngắt của http://stackoverflow.com/questions/14527/xslt-reverse-find-in-a-string? –

Trả lời

19

Trong XSLT 1.0, bạn sẽ cần phải sử dụng một mẫu đệ quy, như thế này:

<xsl:template name="substring-after-last"> 
    <xsl:param name="string" /> 
    <xsl:param name="delimiter" /> 
    <xsl:choose> 
     <xsl:when test="contains($string, $delimiter)"> 
     <xsl:call-template name="substring-after-last"> 
      <xsl:with-param name="string" 
      select="substring-after($string, $delimiter)" /> 
      <xsl:with-param name="delimiter" select="$delimiter" /> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise><xsl:value-of 
        select="$string" /></xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 

và gọi nó như thế này:

<xsl:call-template name="substring-after-last"> 
    <xsl:with-param name="string" select="'M:Namespace.Class.Method(Something a, Something b)'" /> 
    <xsl:with-param name="delimiter" select="'.'" /> 
</xsl:call-template> 

Trong XSLT 2.0, bạn có thể sử dụng chức năng tokenize() và chỉ cần chọn mục cuối cùng trong chuỗi:

tokenize('M:Namespace.Class.Method(Something a, Something b)','\.')[last()] 
+0

Cảm ơn. Làm cách nào để biết tôi đang sử dụng phiên bản XSLT nào? Tôi đang gọi tất cả điều này từ mã C# (sử dụng lớp XslCompiledTransform). –

+0

Thật không may .NET không hỗ trợ XSLT 2.0 nguyên bản. Trừ khi bạn có các công cụ Saxon.net, XQSharp hoặc 2.0 khác, bạn sẽ cần sử dụng giải pháp 1.0. –

+0

Điều này đã làm các trick, cảm ơn! –

-1

Nếu bạn biết rằng bạn có chính xác hai dấu chấm trong chuỗi của bạn thì bạn có thể thử:

<xsl:value-of select="substring-after(substring-after($str, '.'), '.')" /> 
+0

Điều này sẽ không hoạt động nếu tôi có số lượng tùy ý. trong chuỗi của tôi .. Ví dụ: Component.Something.Else.Class.Method (...) –

1

Dưới đây là một giải pháp hiệu quả hơn O (N) vs O (N^2) cho câu trả lời chấp nhận:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="text"/> 

<xsl:template match="text()" name="skipAfterDots"> 
    <xsl:param name="pTotalString" select="."/> 
    <xsl:param name="pTotalLength" select="string-length(.)"/> 
    <xsl:param name="pPosition" select="1"/> 
    <xsl:param name="pLastFound" select="-1"/> 

    <xsl:choose> 
    <xsl:when test="$pPosition > $pTotalLength"> 
     <xsl:value-of select="substring($pTotalString, $pLastFound + 1)"/> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:variable name="vIsDot" select= 
     "substring($pTotalString, $pPosition, 1) = '.'"/> 

     <xsl:call-template name="skipAfterDots"> 
     <xsl:with-param name="pTotalString" select="$pTotalString"/> 
     <xsl:with-param name="pTotalLength" select="$pTotalLength"/> 
     <xsl:with-param name="pLastFound" select= 
     "$pLastFound * not($vIsDot) + $pPosition * $vIsDot"/> 
     <xsl:with-param name="pPosition" select="$pPosition+1"/> 
     </xsl:call-template> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
</xsl:stylesheet> 

Khi chuyển đổi này được áp dụng trên các tài liệu XML sau:

0.123.
<t>M:Namespace.Class.Method(Something a, Something b)</t> 

sự muốn, kết quả chính xác được sản xuất:

Method(Something a, Something b) 

Giải thích:

Giải pháp này không chứa bất kỳ cuộc gọi đến substring-after() chức năng. Thay vào đó, ở mỗi bước chỉ có một ký tự của chuỗi được so sánh cho sự bình đẳng với ký tự dấu chấm. Bởi vì có tối đa N ký tự, đây là O (N) - phức tạp tuyến tính.

Ngược lại, câu trả lời được chấp nhận gọi hàm substring-after() trên mọi bước. Trong trường hợp xấu nhất có thể có N dấu chấm và do đó điều này sẽ là O (N^N) - bậc hai phức tạp.

Lưu ý: Chúng tôi đưa ra giả định hợp lý rằng trong cả hai giải pháp xác định ký tự thứ k của một chuỗi là O (1).

+1

Nhận xét cũ, nhưng tôi cảm thấy cần phải bình luận: giải pháp được chấp nhận cũng là O (n). Mỗi cuộc gọi đến (một thực hiện lành mạnh) 'contains()' sẽ xem xét thông qua các ký tự hàng đầu cho đến khi nó tìm thấy một dấu chấm. Sau khi tìm thấy một dấu chấm, mọi ký tự mà nó đã xem xét cho đến nay đều bị loại bỏ. Vì vậy, nó sẽ xem xét từng nhân vật nhiều nhất một lần. – nemetroid

+0

@nemetroid: Tôi đang đề cập đến ''. Nếu có 'm' chấm trong chuỗi và độ dài chuỗi là' n', thì thuật toán này là 'O (m * n)' –

+0

Đúng, bạn là chính xác. Tôi không nghĩ rằng 'chuỗi con sau 'sẽ phải xem xét toàn bộ chuỗi (còn lại). – nemetroid

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