【问题标题】:Find and Replace with Unique查找并替换为唯一
【发布时间】:2010-09-07 01:52:54
【问题描述】:

我正在对换行符 (
) 执行查找和替换,并使用以下代码将其替换为段落关闭和段落打开标记:

<xsl:template match="/STORIES/STORY">   
    <component>
        <xsl:if test="boolean(ARTICLEBODY)">
            <p>
                <xsl:call-template name="replace-text">
                        <xsl:with-param name="text" select="ARTICLEBODY"  />
                        <xsl:with-param name="replace" select="'&#10;'" />
                        <xsl:with-param name="by" select="'&lt;/p&gt;&lt;p&gt;'" />
                </xsl:call-template>
            </p>
        </xsl:if>
    </component>
</xsl:template>

<xsl:template name="replace-text">
   <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" disable-output-escaping="yes"/>
      <xsl:call-template name="replace-text">
         <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>

这几乎可以完美运行,除了我真的需要它来删除换行符,因为段落往往被 2 或更多分隔,导致 &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;

是否有可能得到它,以便它在每个段落中只替换一次?

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    鉴于您正在调用的 XPath 函数,我不记得在我的 MSXSL 工作中使用过这些函数,看起来您正在使用与 XPath 2 兼容的处理器。

    如果是这样,XPath 2 不是有一个将正则表达式作为第二个参数的 replace(string, pattern, replacement) 函数吗?

    <xsl:value-of 
        select="replace(string(.), '&#10;(\s|&#10;)*', '&lt;/p&gt;&lt;p&gt;')" />
    

    提供一些示例 Xml 输入并了解您计划使用的处理器可能会有所帮助。

    从您的原始示例看来,重复的段落似乎都只有一个空格前缀。所以像这种轻微的修改可能会减少欺骗。

    <xsl:when test="contains($text, $replace)">
      <xsl:variable name="prefix" select="substring-before($text, $replace)" />
      <xsl:choose>
        <xsl:when test="normalize-string($prefix)!=''">
          <xsl:value-of select="$prefix"/>
          <xsl:value-of select="$by" disable-output-escaping="yes"/>
        </xsl:when>
      </xsl:choose>
      <xsl:call-template name="replace-text">
         <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>
    

    【讨论】:

      【解决方案2】:

      试试这个(XSLT 2.0):

          <xsl:template match="/STORIES/STORY">
              <component>
                  <xsl:if test="boolean(ARTICLEBODY)">
                      <xsl:call-template name="insert_paras">
                          <xsl:with-param name="text" select="ARTICLEBODY/text()"/>
                      </xsl:call-template>
                  </xsl:if>
              </component>
          </xsl:template>
      
          <xsl:template name="insert_paras">
              <xsl:param name="text" />
      
              <xsl:variable name="regex">
                  <xsl:text>&#10;(&#10;|\s)*</xsl:text>
              </xsl:variable>
              <xsl:variable name="tokenized-text" select="tokenize($text, $regex)"/>
      
              <xsl:for-each select="$tokenized-text">
                  <p>
                      <xsl:value-of select="."/>
                  </p>
              </xsl:for-each>
          </xsl:template>
      

      在 XML 标记中使用文字字符串通常是个坏主意,因为您不能保证结果是平衡的。

      【讨论】:

        【解决方案3】:

        disable-output-escaping 本身并不邪恶,但只有少数情况下应该使用它,而这不是其中之一。在 XSLT 中,您使用的是树,而不是标记字符串。这是一个 XSTL 1.0 解决方案:

        <xsl:template match="/STORIES/STORY">
          <component>
            <xsl:if test="ARTICLEBODY">
              <xsl:call-template name="wrap-text">
                <xsl:with-param name="text" select="ARTICLEBODY"/>
                <xsl:with-param name="delimiter" select="'&#10;'"/>
                <xsl:with-param name="element" select="'p'"/>
              </xsl:call-template>
            </xsl:if>
          </component>
        </xsl:template>
        
        <xsl:template name="wrap-text">
          <xsl:param name="text"/>
          <xsl:param name="delimiter"/>
          <xsl:param name="element"/>
        
          <xsl:choose>
            <xsl:when test="contains($text, $delimiter)">
              <xsl:variable name="t" select="substring-before($text, $delimiter)"/>
              <xsl:if test="normalize-space($t)">
                <xsl:element name="{$element}">
                <xsl:value-of select="$t"/>  
              </xsl:element>
              </xsl:if>        
              <xsl:call-template name="wrap-text">
                <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
                <xsl:with-param name="delimiter" select="$delimiter"/>
                <xsl:with-param name="element" select="$element"/>
              </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
              <xsl:if test="normalize-space($text)">
                <xsl:element name="{$element}">
                  <xsl:value-of select="$text"/>  
                </xsl:element>
              </xsl:if>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:template>
        

        【讨论】:

          猜你喜欢
          • 2014-06-27
          • 2012-06-24
          • 2017-04-07
          • 2020-06-07
          • 2017-04-23
          • 1970-01-01
          • 2012-03-01
          • 2018-12-07
          • 2018-01-15
          相关资源
          最近更新 更多