2014-03-26 141 views
1

我正在嘗試使用XSLT 2.0來替換任意數量的子字符串。假設我的XML如下所示:多字符串替換

<scheme_template id="job" 
    use_when_ref="action"> 
    <![CDATA[ 
    <p> 
     @[email protected] Haul is based on 
     <b>@[email protected]:</b> 
    </p> 
    <table class="scheme_job_table"> 
     <tr> 
      <td>2 or less</td> 
      <td>@[email protected]</td> 
     </tr> 
     <tr> 
      <td>3-5</td> 
      <td>@[email protected]</td> 
     </tr> 
     <tr> 
      <td>6 or more</td> 
      <td>@[email protected]</td> 
     </tr> 
    </table> 
    ]]> 
</scheme_template> 

<scheme name="JOB! CHICKEN SOUP FOR THE SOULLESS" 
    copies="1"> 
    <use_scheme_template id_ref="job"> 
     <property id="job.fluff"> 
      Chose 1 of your monsters to make and sell 
      heart-warming books of life-affirming awwwww. 
     </property> 
     <property id="job.stat">Smart</property> 
     <property id="job.low">$4</property> 
     <property id="job.middle">$6</property> 
     <property id="job.high">$8</property> 
    </use_scheme_template> 
</scheme> 

我想使用XSL轉換將所有「屬性」值放入方案模板中。我的(有問題的)XSL看起來像這樣:

<xsl:template match="use_scheme_template" mode="expand_template"> 
    <xsl:param name="template_id" select="@id_ref"/> 
    <xsl:param name="base_text" select="//scheme_template[@id=$template_id]"/> 
    <xsl:variable name="expanded_text"> 
     <xsl:apply-templates select="property" mode="replace_props"> 
      <xsl:with-param name="base_text" select="$base_text"/> 
     </xsl:apply-templates> 
    </xsl:variable> 
    <xsl:value-of select="$expanded_text" disable-output-escaping="yes" /> 
</xsl:template> 

<xsl:template match="property" mode="replace_props"> 
    <xsl:param name="base_text"/> 
    <xsl:value-of select="replace($base_text, concat('@', @id, '@'), text())"/> 
</xsl:template> 

但是,這隻會替換第一個屬性。

我需要做什麼才能在同一個字符串上運行replace任意多次?

+0

請期望輸出XML添加到您的問題 - 我不清楚它應該是什麼樣子。謝謝! –

+0

** 1。**請張貼能讓我們重現問題的代碼。 ** 2。**當您處理它時,考慮簡化示例以便重現問題所需的裸露元素。 ** 3。**我不認爲你想要「*在同一個字符串*上運行替換任意次數」。你可能想要對第一個結果運行第二次替換,等等 - 請參閱:http://stackoverflow.com/questions/22265164/xslt-1-0-string-replace-and-concatenation/22272894 #22272894 –

回答

2

我會考慮用xsl:analyze-string代替replace接近這一點。下面將搜索@[email protected]子的文本中,並與匹配屬性值替換它們(如果這樣的屬性存在),留下文字不變的休息:

<xsl:template match="use_scheme_template" mode="expand_template"> 
    <xsl:param name="template_id" select="@id_ref"/> 
    <xsl:param name="base_text" select="//scheme_template[@id=$template_id]"/> 

    <xsl:variable name="properties" select="property" /> 
    <xsl:variable name="expanded_text"> 
     <xsl:analyze-string select="$base_text" regex="@(.*?)@"> 
     <xsl:matching-substring> 
      <!-- substitute the matching property value, if there is one, 
       or leave untouched if not --> 
      <xsl:value-of select="($properties[@id = regex-group(1)], .)[1]" /> 
     </xsl:matching-substring> 
     <xsl:non-matching-substring> 
      <!-- leave non-matching parts unchanged --> 
      <xsl:value-of select="." /> 
     <xsl:non-matching-substring> 
     </xsl:analyze-string> 
    </xsl:variable> 
    <xsl:value-of select="$expanded_text" disable-output-escaping="yes" /> 
</xsl:template> 
+0

這是太棒了,並且處理特殊字符,而不需要我做任何額外的處理。非常感謝。 – BlairHippo

1

而是開始運用replace_props模板的所有屬性,只考慮其應用到第一個屬性:

<xsl:apply-templates select="property[1]" mode="replace_props"> 
     <xsl:with-param name="base_text" select="$base_text"/> 
    </xsl:apply-templates> 

然後,使實際replace_props模板遞歸。然後,邏輯將創建一個變量,其中包含當前替換的文本。然後,您將檢查是否有以下屬性元素可用。如果是這樣,調用模板遞歸使用新替換的文本,否則輸出的文本:

試試這個開始...

<xsl:template match="property" mode="replace_props"> 
    <xsl:param name="base_text"/> 
    <xsl:variable name="expanded_text" select="replace($base_text, concat('@', @id, '@'), text())"/> 
    <xsl:choose> 
     <xsl:when test="following-sibling::property"> 
      <xsl:apply-templates select="following-sibling::property[1]" mode="replace_props"> 
       <xsl:with-param name="base_text" select="$expanded_text"/> 
      </xsl:apply-templates> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="$expanded_text"/> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

...但是當你運行它,你會發現「工作.low「,」job.middle「和」job.high「值爲空。這是因爲$符號在替換函數中有特殊含義(替換的第二個參數可以使用正則表達式,而第二個參數中的$可用於輸出匹配模式的值)。

這意味着您需要做一些額外的工作才能逃避$符號。試試這個模板代替

<xsl:template match="property" mode="replace_props"> 
    <xsl:param name="base_text"/> 
    <xsl:variable name="text" select="replace(text(), '\$', '\\\$')" /> 
    <xsl:variable name="expanded_text" select="replace($base_text, concat('@', @id, '@'), $text)"/> 
    <xsl:choose> 
     <xsl:when test="following-sibling::property"> 
      <xsl:apply-templates select="following-sibling::property[1]" mode="replace_props"> 
       <xsl:with-param name="base_text" select="$expanded_text"/> 
      </xsl:apply-templates> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="$expanded_text"/> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
+0

這是有效的,非常接近我最終提出的自己。但正如你指出的那樣,我發現它嚴重處理特殊字符,這就是爲什麼我給伊恩勾上了對號。但是,謝謝,我感謝幫助。 – BlairHippo