要素のすべての値の最初と最後の出現に関するコンテキストデータを生成する
質問
次のxmlを指定します:
<container>
<val>2</val>
<id>1</id>
</container>
<container>
<val>2</val>
<id>2</id>
</container>
<container>
<val>2</val>
<id>3</id>
</container>
<container>
<val>4</val>
<id>1</id>
</container>
<container>
<val>4</val>
<id>2</id>
</container>
<container>
<val>4</val>
<id>3</id>
</container>
次のようなものを返したい
2 - 1
2 - 3
4 - 1
4 - 3
ノードセットを使用して、次の方法で最後の出現を取得できました。
exsl:node-set($list)/container[not(val = following::val)]
しかし、最初のものを取得する方法がわかりません。
解決
各<!> quot; <val>
<!> quot;の最初と最後の出現(ドキュメントの順序)を取得するにはグループでは、次のように<xsl:key>
を使用できます。
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="text" />
<xsl:key name="ContainerGroupByVal" match="container" use="val" />
<xsl:variable name="ContainerGroupFirstLast" select="//container[
generate-id() = generate-id(key('ContainerGroupByVal', val)[1])
or
generate-id() = generate-id(key('ContainerGroupByVal', val)[last()])
]" />
<xsl:template match="/">
<xsl:for-each select="$ContainerGroupFirstLast">
<xsl:value-of select="val" />
<xsl:text> - </xsl:text>
<xsl:value-of select="id" />
<xsl:value-of select="' '" /><!-- LF -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
編集#1:これはすぐには明らかにならないかもしれないので、少し説明してください:
-
<container>
は、指定されたkey()
を持つすべての<xsl:variable>
ノードを返します。//container
関数を使用してクエリします。 -
generate-id()
は、すべてが発生する場所です。次のように表示されます。- ドキュメント内の各
key('ContainerGroupByVal', val)
ノード(<!> quot;<xsl:for-each>
<!> quot;)check <!>#8230; - <!>#8230;
<xsl:apply-templates>
が返す最初のノードまたは//
が返す最後のノードと同じ一意のID( - where
/*/container
は、現在の|
に一致する - 一意のIDが一致する場合、選択にノードを含めます
/containers/container
)を持っている場合. | . | .
ノードのセットを返します - ドキュメント内の各
-
key(…)[1]
は出力を行います。key(…)[last()]
でも構いません。
編集#2:Dimitre Novatchevがコメントで正しく指摘しているように、<!> quot; <=> <!> quot;の使用には注意が必要です。 XPath速記。回避できる場合は、ぜひ、そうしてください<!>#8212;部分的には、望ましくないノードを選択する可能性があり、主に、より具体的なXPath式よりも遅いためです。たとえば、ドキュメントが次のようになっている場合:
<containers>
<container><!-- ... --></container>
<container><!-- ... --></container>
<container><!-- ... --></container>
</containers>
その後、<!> quot; <=> <!> quot;を使用する必要があります。または<!> quot; <=> <!> quot; <!> quot; <=> <!> quot;の代わりに。
編集#3:上記の代替構文は次のとおりです。
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="text" />
<xsl:key name="ContainerGroupByVal" match="container" use="val" />
<xsl:variable name="ContainerGroupFirstLast" select="//container[
count(
.
| key('ContainerGroupByVal', val)[1]
| key('ContainerGroupByVal', val)[last()]
) = 2
]" />
<xsl:template match="/">
<xsl:for-each select="$ContainerGroupFirstLast">
<xsl:value-of select="val" />
<xsl:text> - </xsl:text>
<xsl:value-of select="id" />
<xsl:value-of select="' '" /><!-- LF -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
説明:XPathユニオン演算子<!> quot; <=> <!> quot;引数をノードセットに結合します。定義により、ノードセットに重複ノードを含めることはできません<!>#8212;例:<!> quot; <=> <!> quot;正確に1つのノード(現在のノード)を含むノードセットを作成します。
これは、現在のノード(<!> quot;。<!> quot;)からユニオンノードセットを作成する場合、<!> quot; <=> <!> quot;ノードと<!> quot; <=> <!> quot;ノード、現在のノードが他の2つのノードのいずれかと等しい場合(のみ)、ノードカウントは2になります。他のすべての場合、カウントは3になります。
他のヒント
I。 XSLT 1.0
基本的にトマラックのソリューションと同じですが、より理解しやすい また、完全であるため、XMLドキュメントと変換をコピーして貼り付けてから、 <!> quot; Transform <!> quot;お気に入りのXSLT IDEのボタン:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kContByVal" match="container"
use="val"/>
<xsl:template match="/*">
<xsl:for-each select=
"container[generate-id()
=
generate-id(key('kContByVal',val)[1])
]
">
<xsl:variable name="vthisvalGroup"
select="key('kContByVal', val)"/>
<xsl:value-of select=
"concat($vthisvalGroup[1]/val,
'-',
$vthisvalGroup[1]/id,
'
'
)
"/>
<xsl:value-of select=
"concat($vthisvalGroup[last()]/val,
'-',
$vthisvalGroup[last()]/id,
'
'
)
"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
この変換が最初に提供されたXML文書に適用されるとき(整形式になるように編集される):
<t>
<container>
<val>2</val>
<id>1</id>
</container>
<container>
<val>2</val>
<id>2</id>
</container>
<container>
<val>2</val>
<id>3</id>
</container>
<container>
<val>4</val>
<id>1</id>
</container>
<container>
<val>4</val>
<id>2</id>
</container>
<container>
<val>4</val>
<id>3</id>
</container>
</t>
必要な結果が生成されます:
2-1
2-3
4-1
4-3
注意事項:
- グループ化にミュンヒアン法を使用して、
container
の値が同じ要素のセットごとに1つのval
要素を見つけます。 - 同じ
<xsl:for-each-group>
値を持つcurrent-group()
要素のノードリスト全体から、グループ内の最初の<=>要素と最後の<=に必要なデータを出力します>グループ内の要素。
II。 XSLT 2.0
この変換:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"/>
<xsl:template match="/*">
<xsl:for-each-group select="container"
group-by="val">
<xsl:for-each select="current-group()[1], current-group()[last()]">
<xsl:value-of select=
"concat(val, '-', id, '
')"/>
</xsl:for-each>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
上記と同じXMLドキュメントに適用された場合、必要な結果を提供します:
<*>注意事項:
-
<=> XSLT命令の使用。
-
<=>関数の使用。