2

構造と内容が変更される可能性があるという知識を持つ次の xml ファイルがあるとします。

<something>
  <parent>
    <child>Bird is the word 1.</child>
    <child>Curd is the word 2.</child>
    <child>Nerd is the word 3.</child>
  </parent>
  <parent>
    <child>Bird is the word 4.</child>
    <child>Word is the word 5.</child>
    <child>Bird is the word 6.</child>
  </parent>
</something>

提供された文字列のすべてのインスタンスを別のインスタンスに置き換えるために、xquery (および xslt も) を使用する方法が必要です。たとえば、「Bird」という単語を「Dog」に置き換えます。したがって、結果は次のようになります。

<something>
  <parent>
    <child>Dog is the word 1.</child>
    <child>Curd is the word 2.</child>
    <child>Nerd is the word 3.</child>
  </parent>
  <parent>
    <child>Dog is the word 4.</child>
    <child>Word is the word 5.</child>
    <child>Dog is the word 6.</child>
  </parent>
</something>

これが可能かどうかはわかりません。私が行ったすべての試みは、タグを排除しました。この例( http://geekswithblogs.net/Erik/archive/2008/04/01/120915.aspx )も試しましたが、ドキュメント全体ではなくテキスト用です。

助けてください!

アップデート

xslt 2.0 の提案が最適であると思われるため、実行してみました。私の場合に合わせて変更しようとしている間、私は乾き続けています。

xml パラメータを渡して、置換を定義したいと考えています。したがって、次のように xslt を変更します。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:param name="list">
<words>
  <word>
        <search>Bird</search>
    <replace>Dog</replace>
  </word>
      <word>
        <search>word</search>
    <replace>man</replace>
  </word>
</words>
  </xsl:param>


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

<xsl:template match="text()">
  <xsl:param name="chosen" select="." />
<xsl:for-each select="$list//word">
  <xsl:variable name="search"><xsl:value-of select="search" /></xsl:variable>
  <xsl:analyze-string select="$chosen" regex="{$search}">
    <xsl:matching-substring><xsl:value-of select="replace" /></xsl:matching-substring>
    <xsl:non-matching-substring><xsl:value-of select="$chosen"/></xsl:non-matching-substring>
  </xsl:analyze-string>
</xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

結果は次のとおりです。

<something>
  <parent>
    <child>Bird is the word 1.Bird is the word 1.</child>
    <child>Curd is the word 2.Curd is the word 2.</child>
    <child>Nerd is the word 3.Nerd is the word 3.</child>
  </parent>
  <parent>
    <child>Bird is the word 4.Bird is the word 4.</child>
    <child>Word is the word 5.Word is the word 5.</child>
    <child>Bird is the word 6.Bird is the word 6.</child>
  </parent>
</something>

言うまでもありませんが、重複したり間違ったりしたくありません。

助けてください!

4

4 に答える 4

7

XQuery と XSLT の両方を使用できる場合は、おそらくXSLT 2.0 プロセッサを使用しています。もしそうなら、これはうまくいくはずです:

XSLT 2.0

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

    <xsl:param name="search" select="'Bird'"/>
    <xsl:param name="replace" select="'Dog'"/>

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

    <xsl:template match="text()">
        <xsl:analyze-string select="." regex="{$search}">
            <xsl:matching-substring><xsl:value-of select="$replace"/></xsl:matching-substring>
            <xsl:non-matching-substring><xsl:value-of select="."/></xsl:non-matching-substring>
        </xsl:analyze-string>
    </xsl:template>

</xsl:stylesheet>

質問からの XML 入力を使用して、この XSLT は次の出力を生成します。

<something>
   <parent>
      <child>Dog is the word 1.</child>
      <child>Curd is the word 2.</child>
      <child>Nerd is the word 3.</child>
   </parent>
   <parent>
      <child>Dog is the word 4.</child>
      <child>Word is the word 5.</child>
      <child>Dog is the word 6.</child>
   </parent>
</something>

注: 出力の作成時に要素/属性/コメント/処理命令が変更されることはありません。


編集

重複が発生する理由は、2 つの要素xsl:for-eachをループしているためです。word3 の場合、テキストを 3 回出力します。

正規表現を少し違った方法で構築する必要があるだけです:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:param name="list">
        <words>
            <word>
                <search>Bird</search>
                <replace>Dog</replace>
            </word>
            <word>
                <search>word</search>
                <replace>man</replace>
            </word>
        </words>
    </xsl:param>

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

    <xsl:template match="text()">
        <xsl:variable name="search" select="concat('(',string-join($list/words/word/search,'|'),')')"/>
        <xsl:analyze-string select="." regex="{$search}">
            <xsl:matching-substring>
                <xsl:value-of select="$list/words/word[search=current()]/replace"/>
            </xsl:matching-substring>
            <xsl:non-matching-substring>
                <xsl:value-of select="."/>
            </xsl:non-matching-substring>
        </xsl:analyze-string>
    </xsl:template>
</xsl:stylesheet>

これにより、次が生成されます。

<something>
   <parent>
      <child>Dog is the man 1.</child>
      <child>Curd is the man 2.</child>
      <child>Nerd is the man 3.</child>
   </parent>
   <parent>
      <child>Dog is the man 4.</child>
      <child>Word is the man 5.</child>
      <child>Dog is the man 6.</child>
   </parent>
</something>
于 2013-01-30T05:55:32.963 に答える
3

これはそれを行う必要があります:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:param name="findText" select="'Bird'" />
  <xsl:param name="replaceText" select="'Dog'" />

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

  <xsl:template match="text()">
    <xsl:call-template name="string-replace-all">
      <xsl:with-param name="text" select="." />
      <xsl:with-param name="replace" select="$findText" />
      <xsl:with-param name="by" select="$replaceText" />
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="string-replace-all">
    <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" />
        <xsl:call-template name="string-replace-all">
          <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>

</xsl:stylesheet>

パラメータのデフォルト値として 'Bird' と 'Dog' を指定したことに注意してください。結果を簡単に示すことができますが、外部コードからこれらのパラメータの値を渡すことができるはずです。サンプル入力で実行すると、次が生成されます。

<something>
  <parent>
    <child>Dog is the word 1.</child>
    <child>Curd is the word 2.</child>
    <child>Nerd is the word 3.</child>
  </parent>
  <parent>
    <child>Dog is the word 4.</child>
    <child>Word is the word 5.</child>
    <child>Dog is the word 6.</child>
  </parent>
</something>
于 2013-01-30T05:31:54.793 に答える
0

ここに別の XQuery オプションがあります...

declare function local:searchReplace($element as element()) {
  element {node-name($element)}
    {$element/@*,
     for $child in $element/node()
        return 
            if ($child instance of element())
            then
                local:searchReplace($child)
            else 
                replace($child,'Bird','Dog')
    }
};

local:searchReplace(/*)

これにより、XSLT 2.0 の回答と同じ出力も生成されます。

<something>
      <parent>
            <child>Dog is the word 1.</child>
            <child>Curd is the word 2.</child>
            <child>Nerd is the word 3.</child>
      </parent>
      <parent>
            <child>Dog is the word 4.</child>
            <child>Word is the word 5.</child>
            <child>Dog is the word 6.</child>
      </parent>
</something>
于 2013-01-30T06:14:59.510 に答える
0

ドキュメントモデルが文字列解析とは異なることを理解するのがコツだと思います。それができれば、この使用例は XQuery または XSLT で十分に簡単になります。あなた自身の好みは好みの問題です。以下は、XQuery での大雑把なアプローチです。より洗練されたソリューションでは、再帰関数呼び出しを使用する場合があります。http://docs.marklogic.com/4.1/guide/app-dev/typeswitch

let $in := <something>
  <parent>
    <child>Bird is the word 1.</child>
    <child>Curd is the word 2.</child>
    <child>Nerd is the word 3.</child>
  </parent>
  <parent>
    <child>Bird is the word 4.</child>
    <child>Word is the word 5.</child>
    <child>Bird is the word 6.</child>
  </parent>
</something>
return element { node-name($in) } {
  $in/@*,
  for $n in $in/node()
  return typeswitch($n)
  case element(parent) return element { node-name($n) } {
    for $c in $n/node()
    return typeswitch($c)
    case element(child) return element { node-name($c) } {
      replace($c, 'Bird', 'Dog') }
    default return $c }
  default return $n }
于 2013-01-30T04:21:16.873 に答える