4

私は XSLT の初心者です。

私のソース XML は以下のとおりです。

<Passengers>
    <Passenger type="A" id="P1"/>
    <Passenger type="A" id="P2"/>
    <Passenger type="B" id="P3"/>
    <Passenger type="C" id="P4"/>
</Passengers>

出力は次のようになります。

<Pax_Items>
     <Item>
         <Type>A</Type>
         <Count>2</Count>
     </Item>
     <Item>
         <Type>B</Type>
         <Count>1</Count>
     </Item>
     <Item>
         <Type>C</Type>
         <Count>1</Count>
     </Item>
</Pax_Items>

以下のようにXSLTを作成しました

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0" exclude-result-prefixes="xmlns">

    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
        <xsl:variable name="filter" select="'TK,AJ'"/>

    <xsl:template match="Passengers">
        <xsl:element name="Pax_Items">
            <xsl:apply-templates select="Passenger"/>
        </xsl:element>
    </xsl:template>

        <xsl:template match="Passenger">
              <xsl:element name="Item">
                     <xsl:element name="Type">
                           <xsl:value-of select="@type"/>
                     </xsl:element>
                     <xsl:element name="Count">
                           <xsl:value-of select="count(//Passenger[@type=current()/@type])"/>
                     </xsl:element>
              </xsl:element>
    </xsl:template>
</xsl:stylesheet>

上記の XSLT を使用すると、以下の出力が得られます。

<Pax_Items>
  <Item>
    <Type>A</Type>
    <Count>2</Count>
  </Item>
  <Item>
    <Type>A</Type>
    <Count>2</Count>
  </Item>
  <Item>
    <Type>B</Type>
    <Count>1</Count>
  </Item>
  <Item>
    <Type>C</Type>
    <Count>1</Count>
  </Item>
</Pax_Items>

重複する要素を省略またはスキップするにはどうすればよいですか? 助けてください。

4

2 に答える 2

7

これは実際にはグループ化の問題の良い例です。XSLT1.0では、グループ化を行う最も効率的な方法は「Muenchian Grouping」と呼ばれる手法を使用することであるため、これについて学ぶ価値があるかもしれません。

この場合、Passenger要素を@type属性でグループ化するため、これを行うためのキーを定義します。

<xsl:key name="Passengers" match="Passenger" use="@type"/>

次に、 @type属性のグループ内でその要素が最初に出現するPassenger要素を選択する必要があります。これは次のように行われます。

<xsl:apply-templates 
    select="Passenger[generate-id() = generate-id(key('Passengers', @type)[1])]"/>

ノードの一意のIDを生成し、2つのノードを比較できるようにするgenerate-idの使用に注意してください。

次に、グループ内の発生数をカウントするのは簡単です。

<xsl:value-of select="count(key('Passengers', @type))"/>

これが完全なXSLTです

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
   <xsl:key name="Passengers" match="Passenger" use="@type"/>

   <xsl:template match="Passengers">
      <Pax_Items>
         <xsl:apply-templates select="Passenger[generate-id() = generate-id(key('Passengers', @type)[1])]"/>
      </Pax_Items>
   </xsl:template>

   <xsl:template match="Passenger">
      <Item>
         <Type>
            <xsl:value-of select="@type"/>
         </Type>
         <Count>
            <xsl:value-of select="count(key('Passengers', @type))"/>
         </Count>
      </Item>
   </xsl:template>
</xsl:stylesheet>

サンプルXMLに適用すると、次のように出力されます。

<Pax_Items>
   <Item>
      <Type>A</Type>
      <Count>2</Count>
   </Item>
   <Item>
      <Type>B</Type>
      <Count>1</Count>
   </Item>
   <Item>
      <Type>C</Type>
      <Count>1</Count>
   </Item>
</Pax_Items>

また、静的要素を出力するためにxsl:elementを使用する本当の理由はないことに注意してください。要素を直接書き出すだけです。

于 2012-10-25T13:24:12.177 に答える
2

passengerテンプレートを次のように更新します。重複ノードをチェックするif条件を追加しました。

<xsl:template match="Passenger">
    <xsl:if test="not(preceding-sibling::Passenger[@type = current()/@type])">
      <xsl:element name="Item">
        <xsl:element name="Type">
          <xsl:value-of select="@type"/>
        </xsl:element>
        <xsl:element name="Count">
          <xsl:value-of select="count(//Passenger[@type=current()/@type])"/>
        </xsl:element>
      </xsl:element>
    </xsl:if>
  </xsl:template>
于 2012-10-25T13:10:13.187 に答える