用XSLT字符串替换字符串(replace a string with a string with

2019-09-22 07:18发布

我想用一个字符串替换字符串。 我发现,这是否但没有似乎工作的例子。 这是一个样本数据

<Addy>
  <Row>
  <LD>Dwelling, 1</D>
  <LN> East</LN>
  <L>1</L>
  <Tf>Abesinia Passage</Tf>
  </Row>

  <Row>
  <LD>Logde</LD>
  <LN>North </LN>
  <L>1</L>
  <Tf>Abesinia Passage</Tf>
  </Row>
</Addy>

我想,以取代以这种方式下面的字符串。

 Dwelling = FLAT
 Lodge    =  SHOP

下面是我使用的代码。 它只是删除了LD元素的所有值。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:lookup="lookup">

<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>

<lookup:data>
    <LD code="Dwelling">FLAT</LD>
     <LD code="Lodge">SHOP</LD>

</lookup:data>

<xsl:variable name="lookup" select="document('')/*/lookup:data"/>

<xsl:template match="LD/text()">
    <xsl:value-of select="$lookup/LD[@code = current()]" />
</xsl:template>

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

如果施加到上述输入数据时,其产生这样的:

   <Addy>
  <Row>
  <LD></LD>
  <LN> East</LN>
  <L>1</L>
  <Tf>Abesinia Passage</Tf>
  </Row>

  <Row>
  <LD></LD>
  <LN>North </LN>
  <L>1</L>
  <Tf>Abesinia Passage</Tf>
  </Row>
  </Addy>

用适当的代码应该产生预期的结果

   <Addy>
  <Row>
  <LD>FLAT,1</D>
  <LN> East</LN>
  <L>1</L>
  <Tf>Abesinia Passage</Tf>
  </Row>

  <Row>
  <LD>SHOP</LD>
  <LN>North </LN>
  <L>1</L>
  <Tf>Abesinia Passage</Tf>
  </Row>
  </Addy>  

Answer 1:

下面是执行多个替换成一个字符串的XSLT转换-无需扩展功能

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:reps>
  <rep>
   <old>Dwelling</old>
   <new>FLAT</new>
  </rep>
  <rep>
   <old>Lodge</old>
   <new>SHOP</new>
  </rep>
 </my:reps>

 <xsl:variable name="vReps" select="document('')/*/my:reps/*"/>

 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="LD/text()" name="replace">
  <xsl:param name="pText" select="."/>

  <xsl:choose>
   <xsl:when test="not($vReps/old[contains($pText, .)])">
    <xsl:value-of select="$pText"/>
   </xsl:when>
   <xsl:otherwise>
       <xsl:call-template name="multiReplace">
        <xsl:with-param name="pText" select="$pText"/>
        <xsl:with-param name="pReps"
         select="$vReps[contains($pText, old)]"/>
       </xsl:call-template>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

 <xsl:template name="multiReplace">
  <xsl:param name="pText"/>
  <xsl:param name="pReps"/>

  <xsl:choose>
      <xsl:when test="$pReps">
       <xsl:variable name="vRepResult">
         <xsl:call-template name="singleReplace">
           <xsl:with-param name="pText" select="$pText"/>
           <xsl:with-param name="pOld" select="$pReps[1]/old"/>
           <xsl:with-param name="pNew" select="$pReps[1]/new"/>
         </xsl:call-template>
       </xsl:variable>

       <xsl:call-template name="multiReplace">
        <xsl:with-param name="pText" select="$vRepResult"/>
        <xsl:with-param name="pReps" select="$pReps[position() >1]"/>
       </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
       <xsl:value-of select="$pText"/>
      </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

 <xsl:template name="singleReplace">
  <xsl:param name="pText"/>
  <xsl:param name="pOld"/>
  <xsl:param name="pNew"/>

  <xsl:if test="$pText">
   <xsl:choose>
    <xsl:when test="not(contains($pText, $pOld))">
     <xsl:value-of select="$pText"/>
    </xsl:when>
    <xsl:otherwise>
     <xsl:value-of select="substring-before($pText, $pOld)"/>
     <xsl:value-of select="$pNew"/>
     <xsl:call-template name="singleReplace">
       <xsl:with-param name="pText" select="substring-after($pText, $pOld)"/>
       <xsl:with-param name="pOld" select="$pOld"/>
       <xsl:with-param name="pNew" select="$pNew"/>
     </xsl:call-template>
    </xsl:otherwise>
   </xsl:choose>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

当这种转化应用所提供的XML文档:

<Addy>
    <Row>
        <LD>Dwelling, 1</LD>
        <LN> East</LN>
        <L>1</L>
        <Tf>Abesinia Passage</Tf>
    </Row>
    <Row>
        <LD>Lodge</LD>
        <LN>North </LN>
        <L>1</L>
        <Tf>Abesinia Passage</Tf>
    </Row>
</Addy>

在想,正确的结果产生:

<Addy>
   <Row>
      <LD>FLAT, 1</LD>
      <LN> East</LN>
      <L>1</L>
      <Tf>Abesinia Passage</Tf>
   </Row>
   <Row>
      <LD>SHOP</LD>
      <LN>North </LN>
      <L>1</L>
      <Tf>Abesinia Passage</Tf>
   </Row>
</Addy>

重要提示

该解决方案是完整和正确的。 肖恩的是相当肤浅的。

通过比较这两个方案,当下面的XML文档应用的结果

<Addy>
    <Row>
        <LD>Dwelling, Lodge, 1</LD>
        <LN> East</LN>
        <L>1</L>
        <Tf>Abesinia Passage</Tf>
    </Row>
    <Row>
        <LD>Lodge, Dwelling</LD>
        <LN>North </LN>
        <L>1</L>
        <Tf>Abesinia Passage</Tf>
    </Row>
</Addy>

肖恩的解决方案producces不正确的替换

<Addy>
   <Row>
      <LD>FLAT, Lodge, 1</LD>
      <LN> East</LN>
      <L>1</L>
      <Tf>Abesinia Passage</Tf>
   </Row>
   <Row>
      <LD>Lodge, FLAT</LD>
      <LN>North </LN>
      <L>1</L>
      <Tf>Abesinia Passage</Tf>
   </Row>
</Addy>

这个答案目前,正确的解决方案,产生正确的更换:

<Addy>
   <Row>
      <LD>FLAT, SHOP, 1</LD>
      <LN> East</LN>
      <L>1</L>
      <Tf>Abesinia Passage</Tf>
   </Row>
   <Row>
      <LD>SHOP, FLAT</LD>
      <LN>North </LN>
      <L>1</L>
      <Tf>Abesinia Passage</Tf>
   </Row>
</Addy>

说明

  1. 身份规则的拷贝“原样”每节点的匹配对于其被选择用于executiom。

  2. 它是由一个单一的模板匹配任何的任何文本节点孩子重写LD在更换必须完成的节点-元素。

  3. 这如果匹配的文本节点contais任何的模板检查old (字符串值),作为全球在线指定my:reps元素。 为方便起见,所有my:reps/rep元素都在名为全局变量被选中$vReps和被引用过这个变量。 如果这些串被包含在当前节点中,然后将其复制到输出。

  4. 如果有至少一个$vReps/old元素,其字符串值包含在当前匹配文本节点,那么我们必须做的替代品。 我们称名模板"multiReplace"执行中的当前文本节点的所有替换。 我们通过这个模板参数的当前文本节点,所有的节点集$vReps/rep元素的字符串值的,其old孩子包含在当前文本节点-这些都是要进行所有的替换。

  5. multiReplace模板调用一个命名模板singleReplace做的第一件更换,并捕获结果在一个名为变量$vRepResult 。 这包含在替换的结果$pText (字符串值)出现的所有 $pReps[1]/old用的字符串值$pReps[1]/new 。 然后multiReplace模板递归调用自己与作为流传至今的替代品的结果$pText参数,并要做出的节点集替代的从第一置换被排除-为$pReps参数。 “停止条件”这个递归是当$pReps参数变为空节点集。

  6. singleReplace模板做什么它的名字一样-它取代其字符串中包含的$pText参数等于任何字符串$pOld与包含在字符串参数pNew参数。 替换的数目可以是大于一的,但它们都是用于单个替换规范==>由此而得名singleReplace 。 这些替代在停止状态递归的方式再次完成时$pText非空,并且仍然含有$pOld



Answer 2:

与现有的代码的问题是,这条线

<xsl:value-of select="$lookup/LD[@code = current()]" />

如果有一个LD元素,它的文本等于上下文节点的全部文本只会发出任何东西。 所以谓语需要使用contains()而不是=

使用XSLT 2.0,您可以按如下改变这个模板:

<xsl:template match="LD/text()">
    <xsl:variable name="LD" select="$lookup/LD[contains(current(), @code)]" />
    <xsl:value-of select="replace(., $LD/@code, $LD/text())" />
</xsl:template>

如果您无法使用XSLT 2.0,您可以使用EXSLT STR:更换() ,而不是XSLT 2.0的版本。

这假定code属性值不包含像任何特殊字符.$等,这将在正则表达式专门解释。

它还假定不超过一个代码将出现在任何LD /文()节点。



Answer 3:

LarsH的解决方案是一个很好的一个。 尝试使用EXSLT是否支持它。 如果不支持,你的XSLT引擎是微软,那么这种XSLT 1.0样式表...

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:l="http://stackoverflow.com/questions/12360735"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  exclude-result-prefixes="xsl l msxsl" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="lookup">
  <l:map pattern="Dwelling" replacement="FLAT" />
  <l:map pattern="Lodge"    replacement="SHOP" />
</xsl:variable>  

<xsl:template match="LD/text()">
  <xsl:choose>
    <xsl:when test="contains(.,msxsl:node-set($lookup)/l:map/@pattern)">
      <xsl:variable name="hay-stack" select="." />
      <xsl:for-each select="(msxsl:node-set($lookup)/l:map[contains($hay-stack,@pattern)])[1]">
        <xsl:value-of select="concat(
          substring-before($hay-stack,@pattern),
          @replacement,
          substring-after($hay-stack,@pattern))" />
      </xsl:for-each>  
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="." />
    </xsl:otherwise>  
  </xsl:choose>  
</xsl:template>

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

...当应用于此输入...

<Addy>
  <Row>
  <LD>Dwelling, 1</LD>
  <LN> East</LN>
  <L>1</L>
  <Tf>Abesinia Passage</Tf>
  </Row>

  <Row>
  <LD>Lodge</LD>
  <LN>North </LN>
  <L>1</L>
  <Tf>Abesinia Passage</Tf>
  </Row>
</Addy>

... ...产量

<Addy>
  <Row>
    <LD>FLAT, 1</LD>
    <LN> East</LN>
    <L>1</L>
    <Tf>Abesinia Passage</Tf>
  </Row>
  <Row>
    <LD>Lodge</LD>
    <LN>North </LN>
    <L>1</L>
    <Tf>Abesinia Passage</Tf>
  </Row>
</Addy>

如果不是微软,你不能使用EXSLT,然后用这个样式表...

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:l="http://stackoverflow.com/questions/12360735"
  exclude-result-prefixes="xsl l" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="lookup">
  <l:map pattern="Dwelling" replacement="FLAT" />
  <l:map pattern="Lodge"    replacement="SHOP" />
</xsl:variable>  

<xsl:template match="LD/text()">
  <xsl:choose>
    <xsl:when test="contains(.,document('')/*/xsl:variable[@name="lookup"]/l:map/@pattern)">
      <xsl:variable name="hay-stack" select="." />
      <xsl:for-each select="(document('')/*/xsl:variable[@name="lookup"]/l:map[contains($hay-stack,@pattern)])[1]">
        <xsl:value-of select="concat(
          substring-before($hay-stack,@pattern),
          @replacement,
          substring-after($hay-stack,@pattern))" />
      </xsl:for-each>  
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="." />
    </xsl:otherwise>  
  </xsl:choose>  
</xsl:template>

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>


文章来源: replace a string with a string with xslt
标签: xml xslt xpath