Thay thế chuỗi XSLT


85

Tôi thực sự không biết XSL nhưng tôi cần sửa mã này, tôi đã giảm nó để làm cho nó đơn giản hơn.
Tôi nhận được lỗi này

Hàm XSLT / XPath không hợp lệ

trên dòng này

<xsl:variable name="text" select="replace($text,'a','b')"/>

Đây là XSL

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:inm="http://www.inmagic.com/webpublisher/query" version="1.0">
    <xsl:output method="text" encoding="UTF-8" />

    <xsl:preserve-space elements="*" />
    <xsl:template match="text()" />

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

        <xsl:for-each select="mosObj">
          'Notes or subject' 
           <xsl:call-template
                name="rem-html">
                <xsl:with-param name="text" select="SBS_ABSTRACT" />
            </xsl:call-template>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="rem-html">
        <xsl:param name="text" />
        <xsl:variable name="text" select="replace($text, 'a', 'b')" />
    </xsl:template>
</xsl:stylesheet>

Bất cứ ai có thể cho tôi biết điều gì sai với nó?


Xin lưu ý rằng replace()hàm có sẵn từ XPath 2.0 (và do đó là XSLT 2.0) trở đi và hỗ trợ thay thế biểu thức chính quy.
Abel

Câu trả lời:


147

replace không khả dụng cho XSLT 1.0.

Codesling có một mẫu để thay thế chuỗi mà bạn có thể sử dụng để thay thế cho hàm:

<xsl:template name="string-replace-all">
    <xsl:param name="text" />
    <xsl:param name="replace" />
    <xsl:param name="by" />
    <xsl:choose>
        <xsl:when test="$text = '' or $replace = ''or not($replace)" >
            <!-- Prevent this routine from hanging -->
            <xsl:value-of select="$text" />
        </xsl:when>
        <xsl:when test="contains($text, $replace)">
            <xsl:value-of select="substring-before($text,$replace)" />
            <xsl:value-of select="$by" />
            <xsl:call-template name="string-replace-all">
                <xsl:with-param name="text" select="substring-after($text,$replace)" />
                <xsl:with-param name="replace" select="$replace" />
                <xsl:with-param name="by" select="$by" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$text" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

được gọi là:

<xsl:variable name="newtext">
    <xsl:call-template name="string-replace-all">
        <xsl:with-param name="text" select="$text" />
        <xsl:with-param name="replace" select="a" />
        <xsl:with-param name="by" select="b" />
    </xsl:call-template>
</xsl:variable>

Mặt khác, nếu bạn thực sự chỉ cần thay thế một ký tự này bằng một ký tự khác, bạn có thể gọi translateký tự có chữ ký tương tự. Một cái gì đó như thế này sẽ hoạt động tốt:

<xsl:variable name="newtext" select="translate($text,'a','b')"/>

Ngoài ra, lưu ý, trong ví dụ này, tôi đã thay đổi tên biến thành "newtext", trong XSLT các biến là bất biến, vì vậy bạn không thể làm tương $foo = $footự như bạn đã làm trong mã gốc của mình.


Cảm ơn Mark, nhưng bây giờ tôi nhận được lỗi này: Một chức năng mở rộng XPath lạ được gọi là
Aximili

@aximili, xin lỗi, có XSLT 1.0 và 2.0 nhầm lẫn, đã chỉnh sửa ... nên chạy ngay bây giờ.
Mark Elliot

19
Câu trả lời này là sai! Hàm thay thế trong XSLT thay thế các KÝ TỰ DUY NHẤT tương ứng, không phải toàn bộ chuỗi! Xem ví dụ ở đây: w3schools.com/xpath/xpath_functions.asp
Jakub

12
@Jakub Bạn đang nghĩ đến translate, không phải replace. Các replacechức năng trong XPath 2.0 xử lý đối số thứ hai của nó như là một biểu hiện thường xuyên và thay thế tất cả các trận đấu của biểu thức đó với chuỗi thay thế nhất định (có thể bao gồm $ntài liệu tham khảo cho các nhóm chụp trong regex). Các translatechức năng (trong 1.0 và 2.0) là một trong đó làm đơn ký tự-cho-single-nhân vật thay thế.
Ian Roberts

6
Dòng thứ 4 trong ví dụ sử dụng không nên <xsl:with-param name="replace" select="'a'" />có dấu ngoặc kép xung quanh a?
DJL

37

Đây là hàm XSLT sẽ hoạt động tương tự như hàm String.Replace () của C #.

Mẫu này có 3 Tham số như bên dưới

text : - chuỗi chính của bạn

thay thế : - chuỗi mà bạn muốn thay thế

bởi : - chuỗi sẽ trả lời bằng chuỗi mới

Dưới đây là các mẫu

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

Mẫu dưới đây cho thấy cách gọi nó

<xsl:variable name="myVariable ">
  <xsl:call-template name="string-replace-all">
    <xsl:with-param name="text" select="'This is a {old} text'" />
    <xsl:with-param name="replace" select="'{old}'" />
    <xsl:with-param name="by" select="'New'" />
  </xsl:call-template>
</xsl:variable>

Bạn cũng có thể tham khảo URL bên dưới để biết chi tiết.


1
Sử dụng xslt 1.0 Bài đăng / mẫu này phù hợp với tôi trong khi Mark Elliot's thì không.
HostMyBus

12

Lưu ý: Trong trường hợp bạn muốn sử dụng thuật ngữ đã được đề cập cho các trường hợp bạn cần thay thế một số lượng lớn các trường hợp trong chuỗi nguồn (ví dụ: các dòng mới trong văn bản dài) thì khả năng cao là bạn sẽ gặp phải StackOverflowExceptionvì đệ quy gọi.

Tôi đã giải quyết vấn đề này nhờ vào kiểu nhúng Java tích hợp sẵn của Xalan (không có vẻ như thế nào trong Saxon ):

<xsl:stylesheet version="1.0" exclude-result-prefixes="xalan str"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xalan="http://xml.apache.org/xalan"
                xmlns:str="xalan://java.lang.String"
        >
...
<xsl:value-of select="str:replaceAll(
    str:new(text()),
    $search_string,
    $replace_string)"/>
...
</xsl:stylesheet>

Xin lỗi nếu tôi bị câm nhưng tôi nhận được:Cannot find a script or an extension object associated with namespace 'xalan://java.lang.String'.
Ian Grainger

Công cụ XSLT của bạn là gì?
Milan Aleksić

3
Nhận xét của tôi dành cho công cụ Java XSLT 1.0 phổ biến nhất Xalan ( xml.apache.org/xalan-j ), hỗ trợ ánh xạ trực tiếp đến các loại có sẵn bên trong Java classpath có sẵn; bạn không thể áp dụng giải pháp của tôi cho .Net stack
Milan Aleksić

@IanGrainger, bạn có thể sử dụng nó với .NET bằng cách thêm một <msxsl:script>khối, có thể gọi bất kỳ phương thức .NET, thư viện nào, v.v. Mặc dù .NET cũng hỗ trợ các chức năng mở rộng EXSLT, vì vậy bạn không cần phải làm như vậy.
Abel

exslt cũng được hỗ trợ trong libxslt và do đó trong tất cả các hậu duệ xsltproc vv ...
Alain Pannetier

7

Bạn có thể sử dụng mã sau khi bộ xử lý của bạn chạy trên .NET hoặc sử dụng MSXML (trái ngược với bộ xử lý dựa trên Java hoặc gốc khác). Nó sử dụng msxsl:script.

Đảm bảo thêm không gian tên xmlns:msxsl="urn:schemas-microsoft-com:xslt"vào gốc xsl:stylesheethoặc xsl:transformphần tử của bạn .

Ngoài ra, liên kết outletvới bất kỳ không gian tên nào bạn thích, chẳng hạn xmlns:outlet = "http://my.functions".

<msxsl:script implements-prefix="outlet" language="javascript">
function replace_str(str_text,str_replace,str_by)
{
     return str_text.replace(str_replace,str_by);
}
</msxsl:script>


<xsl:variable name="newtext" select="outlet:replace_str(string(@oldstring),'me','you')" />

Xin lỗi nếu tôi bị câm, nhưng tôi hiểu prefix outlet is not definedhoặc 'xsl:script' cannot be a child of the 'xsl:stylesheet' element.nếu tôi thay đổi msxsl cho tiền tố của mình. Tôi đoán đây là một số phép thuật XSLT cụ thể của Microsoft?
Ian Grainger

1
@IanGrainger, không phải vậy xsl:script, nhưng msxsl:scriptnó có một không gian tên khác (tôi đã cập nhật câu trả lời của John).
Abel

1

Tôi tiếp tục đánh câu trả lời này. Nhưng không ai trong số họ liệt kê giải pháp dễ dàng nhất cho xsltproc (và có lẽ là hầu hết các bộ xử lý XSLT 1.0):

  1. Thêm tên chuỗi exslt vào biểu định kiểu, tức là:
<xsl:stylesheet
  version="1.0"
  xmlns:str="http://exslt.org/strings"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  1. Sau đó sử dụng nó như:
<xsl:value-of select="str:replace(., ' ', '')"/>

1
Xsltproc trên máy tính của tôi (macOS 10.13) KHÔNG hỗ trợ str:replace()chức năng này. Không có bất kỳ bộ xử lý XSLT 1.0 chính nào khác - Xalan, Saxon 6.5 và Microsoft.
michael.hor257k

0

Rouine khá tốt, tuy nhiên nó khiến ứng dụng của tôi bị treo, vì vậy tôi cần thêm trường hợp:

  <xsl:when test="$text = '' or $replace = ''or not($replace)" >
    <xsl:value-of select="$text" />
    <!-- Prevent thsi routine from hanging -->
  </xsl:when>

trước khi hàm được gọi đệ quy.

Tôi đã nhận được câu trả lời từ đây: Khi thử nghiệm treo trong một vòng lặp vô hạn

Cảm ơn bạn!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.