แทนที่สตริง XSLT


86

ฉันไม่รู้จริงๆว่า XSL แต่ฉันต้องการแก้ไขโค้ดนี้ฉันได้ลดมันลงเพื่อให้ง่ายขึ้น
ฉันได้รับข้อผิดพลาดนี้

ฟังก์ชัน XSLT / XPath ไม่ถูกต้อง

ในบรรทัดนี้

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

นี่คือ 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>

ใครช่วยบอกทีว่ามีอะไรผิดปกติ?


โปรดทราบว่าreplace()ฟังก์ชันนี้สามารถใช้ได้ตั้งแต่ XPath 2.0 (และดังนั้น XSLT 2.0) เป็นต้นไปและรองรับการแทนที่นิพจน์ทั่วไป
Abel

คำตอบ:


150

replace ไม่สามารถใช้ได้กับ XSLT 1.0

Codesling มีเทมเพลตสำหรับการเปลี่ยนสตริงที่คุณสามารถใช้แทนฟังก์ชันได้:

<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>

เรียกว่า:

<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>

ในทางกลับกันหากคุณต้องการเพียงแค่แทนที่อักขระหนึ่งตัวด้วยอีกตัวคุณสามารถเรียกtranslateซึ่งมีลายเซ็นคล้ายกันได้ สิ่งนี้ควรใช้งานได้ดี:

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

นอกจากนี้โปรดทราบว่าในตัวอย่างนี้ฉันเปลี่ยนชื่อตัวแปรเป็น "newtext" ในตัวแปร XSLT ไม่เปลี่ยนรูปดังนั้นคุณจึงไม่สามารถเทียบเท่า$foo = $fooกับที่คุณมีในรหัสเดิมของคุณได้


ขอบคุณ Mark แต่ตอนนี้ฉันได้รับข้อผิดพลาดนี้: มีการเรียกใช้ฟังก์ชันส่วนขยาย XPath ที่ไม่รู้จัก
Aximili

@aximili ขออภัยมี XSLT 1.0 และ 2.0 สับสนแก้ไข ... ควรจะดีไปตอนนี้
Mark Elliot

19
คำตอบนี้ผิด! ฟังก์ชันการแทนที่ใน XSLT จะแทนที่ตัวอักษรเดี่ยวที่สอดคล้องกันไม่ใช่ทั้งสตริง! ดูตัวอย่างได้ที่นี่: w3schools.com/xpath/xpath_functions.asp
Jakub

12
@Jakub คุณกำลังความคิดของไม่ได้translate ฟังก์ชั่นใน XPath 2.0 ถือว่าอาร์กิวเมนต์ที่สองในฐานะที่เป็นนิพจน์ปกติและแทนที่การแข่งขันทั้งหมดของการแสดงออกว่าด้วยสตริงทดแทนที่กำหนด (ซึ่งอาจรวมถึงการอ้างอิงไปยังกลุ่มจับใน regex ไม่) ฟังก์ชั่น (ใน 1.0 และ 2.0) เป็นหนึ่งที่ไม่ตัวเดียวสำหรับตัวเดียวเปลี่ยน replacereplace$ntranslate
Ian Roberts

6
บรรทัดที่ 4 ในตัวอย่างการใช้งานไม่ควร <xsl:with-param name="replace" select="'a'" />มีเครื่องหมายคำพูดรอบ a?
DJL

37

นี่คือฟังก์ชัน XSLT ซึ่งจะทำงานคล้ายกับฟังก์ชัน String.Replace () ของ C #

เทมเพลตนี้มี 3 พารามิเตอร์ดังต่อไปนี้

ข้อความ : - สตริงหลักของคุณ

แทนที่ : - สตริงที่คุณต้องการแทนที่

โดย : - สตริงที่จะตอบกลับด้วยสตริงใหม่

ด้านล่างนี้คือเทมเพลต

<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>

ตัวอย่างด้านล่างแสดงวิธีการเรียก

<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>

คุณยังสามารถอ้างอิงURL ด้านล่างสำหรับรายละเอียด


1
การใช้ xslt 1.0 โพสต์ / เทมเพลตนี้ใช้ได้ผลสำหรับฉันในขณะที่ Mark Elliot ไม่ได้ใช้
HostMyBus

12

หมายเหตุ:ในกรณีที่คุณต้องการใช้ algo ที่กล่าวไปแล้วสำหรับกรณีที่คุณต้องการแทนที่อินสแตนซ์จำนวนมากในสตริงต้นทาง (เช่นบรรทัดใหม่ในข้อความยาว) มีความเป็นไปได้สูงที่คุณจะได้รับStackOverflowExceptionเนื่องจากการเรียกซ้ำ โทร.

ฉันแก้ไขปัญหานี้ได้ด้วยXalan (ไม่ได้ดูวิธีการทำในแซกซอน ) การฝังประเภท Java ในตัว:

<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>

ขออภัยถ้าฉันเป็นคนโง่ แต่ฉันเข้าใจว่า:Cannot find a script or an extension object associated with namespace 'xalan://java.lang.String'.
Ian Grainger

เครื่องยนต์ XSLT ของคุณคืออะไร?
Milan Aleksić

3
ความคิดเห็นของฉันคือสำหรับเอ็นจิ้น Java XSLT 1.0 ยอดนิยม Xalan ( xml.apache.org/xalan-j ) ซึ่งรองรับการแมปโดยตรงกับประเภทที่มีอยู่ภายในคลาสพา ธ Java ที่มีอยู่ คุณไม่สามารถใช้วิธีแก้ปัญหาของฉันสำหรับ. Net stack
Milan Aleksić

@IanGrainger คุณสามารถใช้กับ. NET ได้โดยการเพิ่ม<msxsl:script>บล็อกซึ่งสามารถเรียกเมธอด. NET ไลบรารีและอื่น ๆ แม้ว่า. NET ยังรองรับฟังก์ชันส่วนขยาย EXSLT ดังนั้นคุณจึงไม่จำเป็นต้องทำ
Abel

exsltได้รับการสนับสนุนในlibxsltดังนั้นในตระกูลxsltprocทั้งหมดที่สืบทอดมาเป็นต้น ...
Alain Pannetier

7

คุณสามารถใช้รหัสต่อไปนี้เมื่อโปรเซสเซอร์ของคุณทำงานบน. NET หรือใช้ MSXML (ซึ่งตรงข้ามกับตัวประมวลผลที่ใช้ Java หรือตัวประมวลผลเนทีฟอื่น ๆ ) มันใช้msxsl:script.

อย่าลืมเพิ่มเนมสเปซxmlns:msxsl="urn:schemas-microsoft-com:xslt"ในรูทxsl:stylesheetหรือxsl:transformองค์ประกอบของคุณ

นอกจากนี้การผูกoutletถึง namespace คุณต้องการใด ๆ 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')" />

ขออภัยหากฉันเป็นคนโง่ แต่ฉันเข้าใจprefix outlet is not definedหรือ'xsl:script' cannot be a child of the 'xsl:stylesheet' element.เปลี่ยน msxsl เป็นคำนำหน้า ฉันเดาว่านี่คือเวทมนตร์ XSLT เฉพาะของ Microsoft หรือไม่?
Ian Grainger

1
@IanGrainger ไม่ใช่xsl:scriptแต่msxsl:scriptและมีเนมสเปซที่แตกต่างกัน (ฉันได้อัปเดตคำตอบของ John แล้ว)
Abel

1

ฉันตอบคำตอบนี้ไปเรื่อย ๆ แต่ไม่มีวิธีใดในรายการวิธีแก้ปัญหาที่ง่ายที่สุดสำหรับ xsltproc (และอาจเป็นโปรเซสเซอร์ XSLT 1.0 ส่วนใหญ่):

  1. เพิ่มชื่อสตริง exslt ในสไตล์ชีตเช่น:
<xsl:stylesheet
  version="1.0"
  xmlns:str="http://exslt.org/strings"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  1. จากนั้นใช้มันเช่น:
<xsl:value-of select="str:replace(., ' ', '')"/>

1
xsltproc บนคอมพิวเตอร์ของฉัน (macOS 10.13) ไม่รองรับstr:replace()ฟังก์ชันนี้ ไม่มีโปรเซสเซอร์ XSLT 1.0 หลักอื่น ๆ เช่น Xalan, Saxon 6.5 และ Microsoft
michael.hor257k

0

รูไลน์ค่อนข้างดี แต่มันทำให้แอพของฉันค้างดังนั้นฉันจึงต้องเพิ่มเคส:

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

ก่อนที่ฟังก์ชันจะถูกเรียกซ้ำ

ฉันได้รับคำตอบจากที่นี่: เมื่อการทดสอบแขวนอยู่ในลูปที่ไม่มีที่สิ้นสุด

ขอขอบคุณ!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.