3

文字列を別の文字列に置き換えたい。それを行う例を見つけましたが、うまくいかないようです。これはサンプルデータです

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

3 に答える 3

2

以下は、文字列への複数の置換を実行するための 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 ドキュメントに適用した場合の 2 つのソリューションの結果を比較します

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

Sean のソリューションでは、正しくない置換が生成されます。

<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. アイデンティティ ルールは、実行対象として選択されたすべての一致するノードを「そのまま」コピーします。

  2. これは、任意の要素の任意のテキスト ノードの子 (LD置換が必要なノード) に一致する単一のテンプレートによってオーバーライドされます。

  3. このテンプレートは、グローバルなインライン要素で指定されているように、一致したテキスト ノードにold(文字列値)のいずれかが含まれているかどうかを確認します。my:reps便宜上、すべてのmy:reps/rep要素は という名前のグローバル変数で選択されており、$vRepsこの変数から参照されます。これらの文字列が現在のノードに含まれていない場合は、出力にコピーされます。

  4. $vReps/old現在一致しているテキスト ノードに文字列値が含まれている要素が少なくとも 1 つある場合は、置換を行う必要があります。"multiReplace"現在のテキスト ノードですべての置換を実行する名前のテンプレートを呼び出します。このテンプレートに、現在のテキスト ノードと、現在のテキスト ノードに含まれる子$vReps/repの文字列値を含むすべての要素のノードセットをパラメーターとして渡しoldます。これらはすべて、置換を行うものです。

  5. テンプレートは という名前のmultiReplaceテンプレートを呼び出しsingleReplaceて最初の置換を行い、結果を という名前の変数に取り込みます$vRepResult。これには、出現する$pText すべて$pReps[1]/oldの (の文字列値)を の文字列値で置き換えた結果が含まれます$pReps[1]/new。次に、multiReplaceテンプレートは、これまでに渡された置換の結果を$pTextパラメーターとして使用して再帰的に自身を呼び出し、最初の置換が除外される置換のノードセットをパラメーターとして呼び出し$pRepsます。この再帰の「停止条件」は、$pRepsパラメーターが空のノード セットになったときです。

  6. singleReplaceテンプレートは、その名前が示すとおりに機能します。つまり、パラメーターに含まれる文字列内で、パラメーターに等しい部分文字列を、パラメーターに含まれる文字列に置き換え$pTextます。置換の数は 1 つより多い場合がありますが、それらはすべて単一の置換仕様のためのものです ==> したがって、名前です。置換は、が空ではなく、まだ が含まれている場合に、停止条件を使用して再帰的に行われます。$pOldpNewsingleReplace$pText$pOld

于 2012-09-11T05:12:04.383 に答える
0

既存のコードの問題は、この行

<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 を使用できない場合は、XSLT 2.0 のバージョンの代わりにEXSLT str:replace()を使用できます。

これは、正規表現で特別に解釈される 、 などのcode特殊文字が属性値に含まれていないことを前提としています。.$

また、どの LD/text() ノードにも複数のコードが表示されないことを前提としています。

于 2012-09-10T23:58:53.847 に答える
0

LarsH のソリューションは優れたソリューションです。サポートされている場合は、EXSLT を使用してみてください。サポートされておらず、XSLT エンジンが Microsoft の場合、この 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>

Microsoft ではなく、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>
于 2012-09-11T02:00:33.267 に答える