XSLT dizesi değiştir


86

XSL'yi gerçekten bilmiyorum ama bu kodu düzeltmem gerekiyor, daha basit hale getirmek için küçülttüm.
Bu hatayı alıyorum

Geçersiz XSLT / XPath işlevi

bu hatta

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

Bu XSL'dir

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

Biri bana neyin yanlış olduğunu söyleyebilir mi?


Lütfen replace()işlevin XPath 2.0'dan (ve dolayısıyla XSLT 2.0'dan) itibaren mevcut olduğunu ve normal ifadelerin değiştirilmesini desteklediğini unutmayın.
Abel

Yanıtlar:


150

replace XSLT 1.0 için kullanılamaz.

Kodlama, işlevin yerine geçecek bir dizi değiştirme şablonuna sahiptir :

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

şu şekilde çağrıldı:

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

Öte yandan, kelimenin tam anlamıyla yalnızca bir karakteri diğeriyle değiştirmeniz gerekiyorsa, translatebenzer bir imzaya sahip olanı arayabilirsiniz . Bunun gibi bir şey düzgün çalışmalıdır:

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

Ayrıca, bu örnekte değişken adını "newtext" olarak değiştirdim, XSLT'deki değişkenler değişmezdir, bu nedenle $foo = $fooorijinal kodunuzdaki gibi eşdeğerini yapamazsınız .


Teşekkürler Mark, ama şimdi şu hatayı alıyorum: Bilinmeyen bir XPath uzantı işlevi çağrıldı
Aximili

@aximili, üzgünüm, XSLT 1.0 ve 2.0'ın kafası karıştı, düzenlendi ... şimdi gitmek iyi olur.
Mark Elliot

19
Bu cevap yanlış! XSLT'deki değiştirme işlevi, tüm dizeleri değil, karşılık gelen TEK KARAKTERLER'in yerini alır! Örnek için buraya bakın: w3schools.com/xpath/xpath_functions.asp
Jakub

12
@Jakub Düşünüyorsun translate, değil replace. replaceXPath'daki fonksiyonu olarak 2.0 davranır ikinci bağımsız değişken normal ifade ve yerine geçer (içerebilir belirtilen değiştirme dizesi o ifade tüm maçlar $ndüzenli ifade yakalama gruplarına referanslar). translateİşlev (1.0 ve 2.0'da), tek karakter yerine tek karakter değiştirmeleri yapan işlevdir.
Ian Roberts

6
örnek kullanımdaki 4. satır, <xsl:with-param name="replace" select="'a'" />a'nın etrafındaki tırnak işaretleriyle birlikte olmamalıdır ?
DJL

37

İşte C # 'ın String.Replace () işlevine benzer şekilde çalışacak XSLT işlevi.

Bu şablon aşağıdaki gibi 3 Parametreye sahiptir

metin : - ana dizeniz

replace : - değiştirmek istediğiniz dize

by : - yeni dizge ile yanıt verecek dize

Şablon aşağıdadır

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

Aşağıdaki örnek, nasıl adlandırılacağını gösterir

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

Ayrıntılar için aşağıdaki URL'ye de başvurabilirsiniz .


1
Xslt 1.0 kullanımı Bu gönderi / şablon benim için çalıştı, ancak Mark Elliot'ınki işe yaramadı.
HostMyBus

12

Not: Eğer kaynak dizesinde durumlarda (uzun metinde örneğin yeni çizgiler) çok sayıda değiştirmeniz gerekiyor durumlar için algo zaten bahsedilen kullanmak isteyen durumda olduğu yüksek olasılık sen ile bitireceğiz StackOverflowException, çünkü özyinelemeli arasında aramak.

Bu sorunu Xalan'ın ( Sakson'da nasıl yapılacağına bakmadım ) yerleşik Java tipi yerleştirme sayesinde çözdüm :

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

Aptal oluyorsam özür dilerim ama şunu anlıyorum:Cannot find a script or an extension object associated with namespace 'xalan://java.lang.String'.
Ian Grainger

XSLT motorunuz nedir?
Milan Aleksić

3
Benim yorumum, mevcut Java sınıf yolu içindeki mevcut türlere doğrudan eşlemeyi destekleyen en popüler Java XSLT 1.0 motoru Xalan ( xml.apache.org/xalan-j ) içindi ; çözümümü .Net yığını için uygulayamazsınız
Milan Aleksić

@IanGrainger, <msxsl:script>herhangi bir .NET yöntemini, kitaplığı vb. Çağırabilen bir blok ekleyerek .NET ile kullanabilirsiniz . NET ayrıca EXSLT uzantı işlevlerini desteklese de, buna gerek kalmaz.
Abel

EXSLT da desteklenir libxslt'nin ve dolayısıyla tüm soyundan içinde Xsltproc vs ...
Alain Pannetier

7

İşlemciniz .NET üzerinde çalıştığında veya MSXML kullandığında (Java tabanlı veya diğer yerel işlemcilerin aksine) aşağıdaki kodu kullanabilirsiniz. Kullanır msxsl:script.

Ad alanını xmlns:msxsl="urn:schemas-microsoft-com:xslt"kökünüze xsl:stylesheetveya öğenize eklediğinizden emin olun xsl:transform.

Ek olarak, outletörneğin istediğiniz herhangi bir ad alanına bağlanı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')" />

Aptal davrandıysam özür dilerim, ama önekim için msxsl alırım prefix outlet is not definedveya 'xsl:script' cannot be a child of the 'xsl:stylesheet' element.değiştirirsem. Sanırım bu Microsoft'a özgü XSLT sihri mi?
Ian Grainger

1
@IanGrainger, öyle değil xsl:script, ama msxsl:scriptfarklı bir ad alanına sahip (John'un cevabını güncelledim).
Abel

1

Bu yanıtı bulmaya devam ediyorum. Ancak hiçbiri xsltproc (ve muhtemelen çoğu XSLT 1.0 işlemcisi) için en kolay çözümü listelemiyor:

  1. Exslt dizeleri adını stil sayfasına ekleyin, yani:
<xsl:stylesheet
  version="1.0"
  xmlns:str="http://exslt.org/strings"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  1. O zaman şu şekilde kullanın:
<xsl:value-of select="str:replace(., ' ', '')"/>

1
Bilgisayarımdaki xsltproc (macOS 10.13) işlevi DESTEKLEMEZ str:replace(). Diğer büyük XSLT 1.0 işlemcilerinden hiçbiri - Xalan, Saxon 6.5 ve Microsoft.
michael.hor257k

0

Rutin oldukça iyi, ancak uygulamamın takılmasına neden oluyor, bu yüzden vakayı eklemem gerekiyor:

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

işlev özyinelemeli olarak çağrılmadan önce.

Cevabı buradan aldım: Test sonsuz bir döngüde asılıyken

Teşekkür ederim!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.