4

こんにちは、私は Xslt/Xml の初心者です。

私はそのようなXMLを持っています:

<entry>
 <attribute1>A</attribute1>
 <attribute2>B</attribute2>
</entry>
<entry>
 <attribute1>A</attribute1>
 <attribute2>B</attribute2>
</entry>
<entry>
 <attribute1>C</attribute1>
 <attribute2>D</attribute2>
</entry>
<entry>
 <attribute1>E</attribute1>
 <attribute2>F</attribute2>
</entry>
...

テーブル出力が必要です:

Attribute1 Attribute2 Qty
   A           B       2
   C           D       1
   E           F       1

助けが必要です。一意のエントリを数えて、表に 1 つとして表示する方法がわかりません。

XSLT バージョン 1.0 を使用しています

4

2 に答える 2

4

出発点として、これを短くしてください。

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

    <xsl:key name="keys" match="entry" use="concat(attribute1,'|',attribute2)"/>

    <xsl:template match="/test">
        <xsl:apply-templates select="entry[
          generate-id() 
          = generate-id(key('keys',concat(attribute1,'|',attribute2))[1])]"/>
    </xsl:template>

    <xsl:template match="entry">
        <xsl:value-of select="concat(
            attribute1,' ', 
            attribute2,' ',
            count(key('keys',concat(attribute1,'|',attribute2))),'&#10;')"/>
    </xsl:template> 

</xsl:stylesheet>

XSLTを初めて使用する場合、この変換を理解するには、以下について読む必要があります。

  • xslt出力メソッド
  • xsl:key要素
  • Meunchianグループ化
  • xpathconcatおよびcount関数
  • xpath | 連合
于 2012-06-15T15:31:41.010 に答える
3

I. 単純な XSLT 1.0 変換:

<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:key name="kEntryByChildren" match="entry" use="."/>

 <xsl:template match=
 "entry[not(generate-id() = generate-id(key('kEntryByChildren', .)[1]))]"/>

 <xsl:template match="entry">
  <tr>
   <xsl:apply-templates/>
   <td><xsl:value-of select="count(key('kEntryByChildren', .))"/></td>
  </tr>
 </xsl:template>

 <xsl:template match="entry/*">
   <td><xsl:value-of select="."/></td>
 </xsl:template>

 <xsl:template match="/*">
   <table>
     <xsl:apply-templates/>
   </table>
 </xsl:template>
</xsl:stylesheet>

提供された XML に適用した場合(整形式の XML ドキュメントを取得するために、フラグメントは単一の最上位要素にラップされます):

<t>
    <entry>
        <attribute1>A</attribute1>
        <attribute2>B</attribute2>
    </entry>
    <entry>
        <attribute1>A</attribute1>
        <attribute2>B</attribute2>
    </entry>
    <entry>
        <attribute1>C</attribute1>
        <attribute2>D</attribute2>
    </entry>
    <entry>
        <attribute1>E</attribute1>
        <attribute2>F</attribute2>
    </entry>
</t>

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

<table>
   <tr>
      <td>A</td>
      <td>B</td>
      <td>2</td>
   </tr>
   <tr>
      <td>C</td>
      <td>D</td>
      <td>1</td>
   </tr>
   <tr>
      <td>E</td>
      <td>F</td>
      <td>1</td>
   </tr>
</table>

このトリッキーな XML ドキュメントに適用するとentry(子の値の単純な連結を使用すると、最初の 3 つの要素が「同じ」であると誤って結論付けてしまいます)。

<t>
    <entry>
        <attribute1>AB</attribute1>
        <attribute2>C</attribute2>
    </entry>
    <entry>
        <attribute1>A</attribute1>
        <attribute2>BC</attribute2>
    </entry>
    <entry>
        <attribute1>A</attribute1>
        <attribute2>BC</attribute2>
    </entry>
    <entry>
        <attribute1>C</attribute1>
        <attribute2>D</attribute2>
    </entry>
    <entry>
        <attribute1>E</attribute1>
        <attribute2>F</attribute2>
    </entry>
</t>

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

<table>
   <tr>
      <td>AB</td>
      <td>C</td>
      <td>1</td>
   </tr>
   <tr>
      <td>A</td>
      <td>BC</td>
      <td>2</td>
   </tr>
   <tr>
      <td>C</td>
      <td>D</td>
      <td>1</td>
   </tr>
   <tr>
      <td>E</td>
      <td>F</td>
      <td>1</td>
   </tr>
</table>

説明:

Muenchian グループ化法の適切な使用。

注意してください:

  1. このソリューションは、要素の子の名前と数に依存しないため、entry2 つ以上の子がある場合、または事前に名前が不明なさまざまな数の子がある場合に適用できます。

  2. ここでは、同じ子が同じ値を持つ場合にのみ、すべての子の文字列値の連結が同じであると想定しています。


Ⅱ.完全な XSLT 1.0 ソリューション:

上記の仮定 2. が保証されない場合、これは可能な XSLT 1.0 ソリューションの 1 つです。

<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="entry">
  <xsl:variable name="vChildrenFp">
    <xsl:for-each select="*">
     <xsl:value-of select="concat(., '+')"/>
    </xsl:for-each>
  </xsl:variable>

  <xsl:variable name="vPrecedingSame">
    <xsl:for-each select="preceding-sibling::entry">
     <xsl:variable name="vthisFP">
       <xsl:for-each select="*">
         <xsl:value-of select="concat(., '+')"/>
       </xsl:for-each>
     </xsl:variable>

     <xsl:if test="$vthisFP = $vChildrenFp">1</xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <xsl:if test="not(string($vPrecedingSame))">
      <xsl:variable name="vFollowingSame">
        <xsl:for-each select="following-sibling::entry">
         <xsl:variable name="vthisFP">
           <xsl:for-each select="*">
             <xsl:value-of select="concat(., '+')"/>
           </xsl:for-each>
         </xsl:variable>

         <xsl:if test="$vthisFP = $vChildrenFp">1</xsl:if>
        </xsl:for-each>
      </xsl:variable>

      <tr>
       <xsl:apply-templates/>
       <td><xsl:value-of select="string-length($vFollowingSame)+1"/></td>
      </tr>
  </xsl:if>
 </xsl:template>

 <xsl:template match="entry/*">
   <td><xsl:value-of select="."/></td>
 </xsl:template>

 <xsl:template match="/*">
   <table>
     <xsl:apply-templates/>
   </table>
 </xsl:template>
</xsl:stylesheet>

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

<table>
   <tr>
      <td>A</td>
      <td>B</td>
      <td>2</td>
   </tr>
   <tr>
      <td>C</td>
      <td>D</td>
      <td>1</td>
   </tr>
   <tr>
      <td>E</td>
      <td>F</td>
      <td>1</td>
   </tr>
</table>

説明:

  1. 要素ごとentryに、その子の「フィンガープリント」(FP) を生成しentry、前の兄弟entry要素のいずれにも同じ子のフィンガープリントがない場合は、この要素を処理します。

  2. 「同じ」entry要素のカウントは同様の方法で行われます。同じ子の FP 値を持つ後続の兄弟entry要素については、1 文字 ('1') を出力します。合計カウントは、そのように生成された文字列 (「1」) の文字列長に 1 を加えたものです。


III. 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"
    xmlns:my="my:my" exclude-result-prefixes="my xs">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:param name="pExoticString" select="'+'"/>

 <xsl:template match="/*">
   <table>
     <xsl:for-each-group select="entry" group-by="my:fingerprint(.)">
       <tr>
           <xsl:apply-templates/>
           <td><xsl:value-of select="count(current-group())"/></td>
       </tr>
     </xsl:for-each-group>
   </table>
 </xsl:template>

 <xsl:template match="entry/*">
   <td><xsl:value-of select="."/></td>
 </xsl:template>

 <xsl:function name="my:fingerprint" as="xs:string">
  <xsl:param name="pParent" as="element()"/>

  <xsl:sequence select="string-join($pParent/*, $pExoticString)"/>
 </xsl:function>
</xsl:stylesheet>

このシンプルなソリューションは、複雑なケースを簡単に処理します。最後の XML ドキュメントに適用すると、必要な正しい結果が生成されます。

<table>
   <tr>
            <td>AB</td>
            <td>C</td>
         <td>1</td>
   </tr>
   <tr>
            <td>A</td>
            <td>BC</td>
         <td>2</td>
   </tr>
   <tr>
            <td>C</td>
            <td>D</td>
         <td>1</td>
   </tr>
   <tr>
            <td>E</td>
            <td>F</td>
         <td>1</td>
   </tr>
</table>

説明:

xsl:for-each-groupxsl:functioncurrent-group()およびの適切な使用string-join()

于 2012-06-16T01:36:47.963 に答える