0

そのため、一方の XPath 式が必要なノードを取得し、もう一方の XPath 式が取得しない理由を理解するのに苦労しています。

まず、xml:

<doc>
    <source id="225" clientID="567" matterID="225" level="2" />
    <source id="226" clientID="993" matterID="226" level="2" />
    <dest id="185" level="7" />
    <dest id="226" level="7" />
</doc>

私の xsl テンプレートのキーは次のように定義されています。

<xsl:key name="sourceId" match="//source" use="@id" />
<xsl:key name="destId" match="//dest" use="@id" />
<xsl:key name="destLevel" match="//dest" use="@level" />

私が探しているのは、id で dest ノードに一致するが、異なるレベル属性を持つソース ノードです。頭の中で機能すると考えた適用テンプレートは次のとおりです。

<xsl:apply-templates select="source[key('destId', @id) and not(key('destLevel', @level))]" mode="update" />

しかし、それはうまくいかないようです。同僚は、私が望まないノードに一致する式の周りに not を置くことを提案しました。多くの試行錯誤の後、私はこれがうまくいくかもしれないと考えましたが、効果はありませんでした:

<xsl:apply-templates select="source[not(not(key('destId', @id)) or not(key('destLevel', @level)))]" mode="update" />

これを解決するために必要なことを教えてください。

編集:以前は2番目のクエリでこれを解決したと思っていましたが、間違っていたようです。

====解決策====

Dimitre Novatchev は、これを解決するためのさまざまな方法を詳細に説明していますが、私の最終的な解決策は、実際には彼のものとは少し異なっていました。

要するに、2 つの属性を組み合わせた concat() 関数を使用して仮想キーを作成しました。そうすれば、ID に一致するノードを見つけることができましたが、ID レベルのコンボには一致しませんでした。

追加のキー:

<xsl:key name="destByIdAndLevel" match="//dest" use="concat(@id,'+',@level)" />

apply-template 呼び出しの変更:

<xsl:apply-templates select="source[key('destId', @id) and not(key('destByIdAndLevel',concat(@id,'+',@level)))]" mode="update" /> 
4

2 に答える 2

3

I. この変換:

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

 <xsl:template match="source">
   <xsl:copy-of select=
     "self::*[../dest[@id = current()/@id and not(@level=current()/@level)]]"/>
 </xsl:template>
</xsl:stylesheet>

この XML ドキュメントに適用した場合(source提供された XML ドキュメントに追加された追加の要素 -- より多くのケースを検証するため):

<doc>
 <source id="185" clientID="567" matterID="225" level="7" />
 <source id="225" clientID="567" matterID="225" level="2" />
 <source id="226" clientID="993" matterID="226" level="2" />
 <dest id="185" level="7" />
 <dest id="226" level="7" />
</doc>

必要な正しい結果が生成されます

<source id="226" clientID="993" matterID="226" level="2"/>

Ⅱ.1 つのキーを使用したソリューション:

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

 <xsl:key name="kDestById" match="dest" use="@id"/>

 <xsl:template match="/*">
  <xsl:copy-of select=
   "source[key('kDestById',@id)
         and
           not(@level=key('kDestById',@id)/@level)]"/>
 </xsl:template>
</xsl:stylesheet>

この変換が同じ XML ドキュメント (上記) に適用されると、同じように正しい結果が生成されます。

<source id="226" clientID="993" matterID="226" level="2"/>

III. 2 つのキーを使用したソリューション:

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

 <xsl:key name="kDestById" match="dest" use="@id"/>
 <xsl:key name="kDestByLevel" match="dest" use="@level"/>

 <xsl:template match="source">
  <xsl:copy-of select=
   "self::*
        [key('kDestById',@id)
       and
         key('kDestById',@id)
             [not(count(.|key('kDestByLevel',current()/@level))
                 =
                  count(key('kDestByLevel',current()/@level))
                 )
             ]
        ]"/>
 </xsl:template>
</xsl:stylesheet>

これにより、必要な正しい結果が再び生成されます

 <source id="226" clientID="993" matterID="226" level="2"/>
于 2012-08-11T18:01:37.967 に答える
1
source[key('destId', @id) and not(key('destLevel', @level))]

これにより、一部の宛先ノードと同じ ID を持つソース ノードが与えられ、どの宛先ノードとも同じではないレベルも設定されます。特定の宛先ノードが同じ ID で異なるレベルを持つ必要はないことに注意してください。

私はあなたがこのようなものを探していると思います:

source[set:difference(key('destId', @id), key('destLevel', @level))]

set:difference()は EXSLT からのものです。

于 2012-08-11T18:00:59.410 に答える