要素のすべての値の最初と最後の出現に関するコンテキストデータを生成する

StackOverflow https://stackoverflow.com/questions/807578

  •  03-07-2019
  •  | 
  •  

質問

次の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="'&#10;'" /><!-- 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(/containers/container)を持っている場合
    • where /*/containerは、現在の|
    • に一致する. | . | .ノードのセットを返します
    • 一意のIDが一致する場合、選択にノードを含めます
  • 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="'&#10;'" /><!-- LF -->
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

説明:XPathユニオン演算子<!> quot; <=> <!> quot;引数をノードセットに結合します。定義により、ノードセットに重複ノードを含めることはできません<!>#8212;例:<!> quot; <=> <!> quot;正確に1つのノード(現在のノード)を含むノードセットを作成します。

これは、現在のノード(<!> quot;。<!> quot;)からユニオンノードセットを作成する場合、<!> quot; <=> <!> quot;ノードと<!> quot; <=> <!> quot;ノード、現在のノードが他の2つのノードのいずれかと等しい場合(のみ)、ノードカウントは2になります。他のすべての場合、カウントは3になります。

他のヒント

基本 XPath

//container[position() = 1]  <- this is the first one
//container[position() = last()]  <- this is the last one

XPath関数の詳細セット。

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,
              '&#xA;'
              )
      "/>
       <xsl:value-of select=
        "concat($vthisvalGroup[last()]/val,
              '-',
              $vthisvalGroup[last()]/id,
              '&#xA;'
              )
        "/>
      </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

注意事項

  1. グループ化にミュンヒアン法を使用して、containerの値が同じ要素のセットごとに1つのval要素を見つけます。
  2. 同じ<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, '&#xA;')"/>
        </xsl:for-each>
    </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

上記と同じXMLドキュメントに適用された場合、必要な結果を提供します

<*>

注意事項

  1. <=> XSLT命令の使用。

  2. <=>関数の使用。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top