3

編集: ESXLT機能にもアクセスできます。

文字列トークンの 2 つのノード セットがあります。1 つのセットには、次のような値が含まれます。

/Geography/North America/California/San Francisco
/Geography/Asia/Japan/Tokyo/Shinjuku

もう 1 つのセットには、次のような値が含まれます。

/Geography/North America/
/Geography/Asia/Japan/

私の目標は、2 つの間の「一致」を見つけることです。セット 1 のいずれかの文字列がセット 2 の文字列で始まる場合に一致します。たとえば、/Geography/North America/California/San Francisco/Geography/North America/の間で一致が作成されます。セット 2 の文字列で始まります。

サードパーティの拡張機能を使用して、ワイルドカードを使用して文字列を比較できます。Xpath 内ですべて正規表現を使用することもできます。

私の問題は、両方のセットのすべてのノード間で関数を使用して選択する Xpath をどのように構成するかです。XSL も実行可能なオプションです。

このXPATH:

count($set1[.=$set2])

set1 と set2 の間の交差の数が得られますが、これは 1 対 1 の比較です。ノードを比較する他の手段を使用することは可能ですか?

編集:私はこれを機能させましたが、他のサードパーティの拡張機能を使用して同じ結果を得るために不正行為をしています。これを実現するための他の方法にまだ興味があります。

4

4 に答える 4

2

これ:

<xsl:variable name="matches" select="$set1[starts-with(., $set2)]"/>

テキスト値が $set2 のノードのテキスト値で始まる$matchesすべてのノードを含むノードセットに設定されます。$set1それがあなたが探しているものですよね?

編集:

まあ、私はこれについて間違っています。理由は次のとおりです。

starts-withは、その 2 つの引数が両方とも文字列であることを期待しています。そうでない場合は、関数を評価する前にそれらを文字列に変換します。

引数の 1 つとしてノード セットを指定すると、セット内の最初のノードのテキスト値であるノード セットの文字列値が使用されます。したがって、上記で$set2は、検索されることはありません。リスト内の最初のノードのみが検査されるため、述語は 内$set1の最初のノードの値で始まる内のノードのみを検索します$set2

このパターン (ここ数日でよく使用している)が機能するため、誤解されました。

<xsl:variable name="hits" select="$set1[. = $set2]"/>

しかし、その述語は、テキスト値間ではなく、ノードセット間の比較を使用しています。

これを行う理想的な方法は、述語をネストすることです。つまり、「値が ... で始まる$set1ノードがあるすべてのノードを検索したい」ということで$set2あり、ここで XPath が機能しなくなります。何から始まる?書きたいことは次のようなものです。

<xsl:variable name="matches" select="$set1[$set2[starts-with(?, .)]]"/>

?外側の述語によって現在テストされているノードを返すために記述できる式がないだけです。(私が盲目的に明白なものを見逃していない限り。)

必要なものを取得するには、各ノードを個別にテストする必要があります。

<xsl:variable name="matches">
  <xsl:for-each select="$set1">
    <xsl:if test="$set2[starts-with(current(), .)]">
      <xsl:copy-of select="."/>
    </xsl:if>
  </xsl:for-each>
</xsl:variable>

これは、ノードセットではなく結果ツリーのフラグメントに評価されるため、満足のいく解決策ではありません。XPath 式で変数を使用する場合は、拡張関数 ( などmsxsl:node-set) を使用して RTF をノード セットに変換する必要があります。

于 2008-11-07T19:19:59.117 に答える
1

一致数を見つけるためのシンプルで純粋な XSLT 1.0 ソリューション (拡張機能は不要) があります

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

    <xsl:template match="/">
        <xsl:variable name="vStars">
            <xsl:for-each select="*/regions/*">
                <xsl:for-each select="/*/cities/*[starts-with(.,current())]">
                    <xsl:value-of select="'*'"/>
                </xsl:for-each>
            </xsl:for-each>
        </xsl:variable>

        <xsl:value-of select="string-length($vStars)"/>
    </xsl:template>
</xsl:stylesheet>

この変換が次の XML ドキュメントに適用される場合:

<t>
    <cities>
        <city>/Geography/North America/California/San Francisco</city>
        <city>/Geography/Asia/Japan/Tokyo/Shinjuku</city>
    </cities>
    <regions>
        <region>/Geography/North America/</region>
        <region>/Geography/Asia/Japan/</region>
    </regions>
</t>

正しい結果が生成されます。

2

見つかった一致ごとに 1 文字 (アスタリスク) が生成され、これらすべてのアスタリスクが$vStars変数の内容を形成することに注意してください。次に、単純にその を出力しstring-length()ます。

于 2008-12-05T23:14:26.663 に答える
0

ロバートの最後xsl:variableは、一致するテキスト値を含む結果ツリーのフラグメントを取得するのに適していますが、(彼が示唆するように) EXSLT または MS 拡張を XSLT 1.0 に使用して RTF をノード セットに変換しない限り、一致するテキスト ノード。

これは、セット 2 のノードがその一部または全部に一致するセット 1 のテキスト ノードの数を示すために、私が提供したサンプル入力ドキュメントを繰り返す、以前の応答で言及した XSLT スタイルシートです。

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

  <xsl:output indent="yes" method="text"/>

  <xsl:template match="/">
    <xsl:call-template name="count-matches">
      <xsl:with-param name="set1-node" select="sets/set[1]/text[1]"/>
      <xsl:with-param name="set2-node" select="sets/set[2]/text[1]"/>
      <xsl:with-param name="total-count" select="0"/>
    </xsl:call-template>
    <xsl:text>
</xsl:text>
  </xsl:template>

  <xsl:template name="count-matches">
    <xsl:param name="set1-node"/>
    <xsl:param name="set2-node"/>
    <xsl:param name="total-count" select="0"/>
    <xsl:variable name="this-count">
      <xsl:choose>
        <xsl:when test="contains($set1-node, $set2-node)">
          <xsl:value-of select="1"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="0"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$set2-node/following-sibling::text">
        <xsl:call-template name="count-matches">
          <xsl:with-param name="set1-node"
                          select="$set1-node"/>
          <xsl:with-param name="set2-node"
                          select="$set2-node/following-sibling::text[1]"/>
          <xsl:with-param name="total-count"
                          select="$total-count + $this-count"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$set1-node/following-sibling::text">
        <xsl:call-template name="count-matches">
          <xsl:with-param name="set1-node"
                          select="$set1-node/following-sibling::text[1]"/>
          <xsl:with-param name="set2-node"
                          select="$set2-node/preceding-sibling::text[last()]"/>
          <xsl:with-param name="total-count"
                          select="$total-count + $this-count"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$total-count + $this-count"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

特に簡潔ではありませんが、XSLT ではプログラマーが既に定義された変数に新しい値を割り当てることができないため、再帰が必要になることがよくあります。XSLT 1.0 で、Zack が要求した並べ替えのカウントを取得する方法がわかりませんxsl:for-each

于 2008-11-08T22:20:52.373 に答える
-1

上記のXPathを機能させることができなかったと思います。2 つのノードセットを初期化するために、次の XML ドキュメントから始めました。

<?xml version="1.0"?>
<sets>
  <set>
    <text>/Geography/North America/California/San Francisco</text>
    <text>/Geography/Asia/Japan/Tokyo/Shinjuku</text>
  </set>
  <set>
    <text>/Geography/North America/</text>
    <text>/Geography/Asia/Japan/</text>
  </set>
</sets>

このスタイルシートはロバートのソリューションを実装する必要があると思いますが、「1」のカウントしか得られません。

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

  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:variable name="set1" select="sets/set[1]/text/text()"/>
    <xsl:variable name="set2" select="sets/set[2]/text/text()"/>
    <xsl:value-of select="count($set1[starts-with(., $set2)])"/>
    <xsl:text>
</xsl:text>
  </xsl:template>

</xsl:stylesheet>

再帰テンプレートを使用し、指定された入力ドキュメントで正しいカウント「2」を生成するスタイルシートを作成しましたが、ロバートの回答よりもはるかにエレガントではありません。XPath を機能させることができさえすれば、常に学びたいと思っています。

于 2008-11-07T23:10:17.220 に答える