【问题标题】:How to remove the first occurrence of a word with XSLT?如何使用 XSLT 删除第一次出现的单词?
【发布时间】:2020-07-07 09:48:40
【问题描述】:

给定以下 XML 文档:

<books>
  <book>
   <name>The problem of the ages</name>
  </book>
  <book>
   <name>Filtering the tap</name>
  </book>
  <book>
   <name>Legend of Atlantis</name>
  </book>
</books>

我想从每本书的名称中删除第一个“the”。输出示例:

<library>
  <record>problem of the ages</record>
  <record>Filtering tap</record>
  <record>Legend of Atlantis</record>
</library>

如何使用单个 XSLT 实现这一目标?

【问题讨论】:

    标签: xslt xslt-2.0 xslt-3.0


    【解决方案1】:

    鉴于世界上存在不同的语言,很难确定一个词是什么。但是,XSLT/XPath 2 和更高版本中使用的正则表达式语言允许您匹配 \w 字母数字字母,所以

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:fn="http://www.w3.org/2005/xpath-functions"
        exclude-result-prefixes="#all"
        version="3.0">
        
      <xsl:param name="word-to-eliminate" as="xs:string" select="'the'"/>
      
      <xsl:output indent="yes"/>
    
      <xsl:mode on-no-match="shallow-copy"/>
    
      <xsl:template match="book/name">
          <xsl:copy>
              <xsl:apply-templates select="analyze-string(., $word-to-eliminate, 'i')" mode="eliminate-first"/>
          </xsl:copy>
      </xsl:template>
      
      <xsl:template match="fn:match[1]" mode="eliminate-first"/>
      
      <xsl:template match="fn:non-match[preceding-sibling::node()[1][. is root()/descendant::fn:match[1]]]" mode="eliminate-first">
          <xsl:value-of select="replace(., '^\s', '')"/>
      </xsl:template>
    
    </xsl:stylesheet>
    

    可能在 XSLT 3 中有所帮助,或者可以在 XSLT 2 中以类似的方式使用xsl:analyze-string 来实现。

    或者,如果可以将任何空格视为单词分隔符,并且结果中您只希望剩余单词之间有一个空格,那么

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:fn="http://www.w3.org/2005/xpath-functions"
        exclude-result-prefixes="#all"
        version="3.0">
        
      <xsl:param name="word-to-eliminate" as="xs:string" select="'the'"/>
      
      <xsl:output indent="yes"/>
    
      <xsl:mode on-no-match="shallow-copy"/>
    
      <xsl:template match="book">
          <record>
              <xsl:value-of 
                select="analyze-string(name, '\s+')
                        !
                        (fn:non-match 
                         except 
                         fn:non-match[lower-case(.) = $word-to-eliminate][1]
                        )"/>
          </record>
      </xsl:template>
      
    </xsl:stylesheet>
    

    【讨论】:

    • 我对第二种情况感兴趣,因为它似乎更容易理解。但是,如果我“只希望剩余单词之间有一个空格”,您说它适用。如果我想保留空格数怎么办?例如,从 'beforetheappleofthedragon' 中删除第一个 'the' 应该会导致 'beforeappleof 龙'。
    • 如果第一个案例解决了问题然后使用它,不要期望一个简单问题的更简单的解决方案可以适应更复杂的需求。
    • 另外,如果您能解释一下 analyze-string(name, '\s+') ! (fn:non-match except fn:non-match[lower-case(.) = $word-to-eliminate][1] ) 的作用,我将不胜感激。
    猜你喜欢
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-21
    • 1970-01-01
    • 1970-01-01
    • 2022-12-18
    • 2014-10-22
    相关资源
    最近更新 更多