1

ここでもう一度助けを求めたいと思います。これが私のサンプル入力XMLです:

<Report>
  <RecordValues>
    <Record>
        <FieldValue fieldName="firm_name" fieldValue="Firm_1"/>
        <FieldValue fieldName="firm_number" fieldValue="11"/>
        <FieldValue fieldName="prepared_by" fieldValue="PARKER"/>
        <FieldValue fieldName="contact_number" fieldValue="123456789"/>
        <FieldValue fieldName="trade_date" fieldValue="2010-10-17"/>
        <FieldValue fieldName="symbol" fieldValue="ADM"/>
    </Record>
    <Record>
    <FieldValue fieldName="firm_name" fieldValue="Firm_1"/>
        <FieldValue fieldName="firm_number" fieldValue="11"/>
        <FieldValue fieldName="prepared_by" fieldValue="PARKER"/>
        <FieldValue fieldName="contact_number" fieldValue="123456789"/>
        <FieldValue fieldName="trade_date" fieldValue="2010-10-16"/>
        <FieldValue fieldName="symbol" fieldValue="ACW"/>
    </Record>
    <Record>
        <FieldValue fieldName="firm_name" fieldValue="Firm_2"/>
        <FieldValue fieldName="firm_number" fieldValue="12"/>
        <FieldValue fieldName="prepared_by" fieldValue="EDWARDS"/>
        <FieldValue fieldName="contact_number" fieldValue="123456780"/>
        <FieldValue fieldName="trade_date" fieldValue="2010-10-19"/>
        <FieldValue fieldName="symbol" fieldValue="ADS"/>
    </Record>
  </RecordValues>
</Report>

取得する必要のある出力は次のとおりです。

A Firm_1 11
B PARKER 123456789
C 2010-10-17 ADM
C 2010-10-16 ACW
T 4
A Firm_2 12
B EDWARDS 123456780
C 2010-10-19 ADS
T 3

ご覧のとおり、レコードを「firm_name」または「firm_number」でグループ化する必要があります。各グループには、タイプ「A」のレコードが1つ、タイプ「B」のレコードが1つ、タイプ「C」のレコードが複数ある必要があります。レコード「T」は、レコード「T」のない各グループの合計です。入力XMLはすでにソートされています。レコードをグループ化するミュンチアンメソッドを見つけましたが、何も成功しませんでした。明らかに、私は何か間違ったことをしています。これが私が書いたXSLTです:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="text"/>
   <xsl:strip-space elements="*"/>

   <xsl:key name="value-by-firm" match="Report/RecordValues/Record/FieldValue" use="firm_number"/>
  <xsl:template match="Record">
   <xsl:for-each select="FieldValue/@fieldValue[count(. | key('value-by-firm', firm_number))]">
    <xsl:text>A </xsl:text>
    <xsl:value-of select="firm_name"/>
    <xsl:text> </xsl:text>
    <xsl:value-of select="firm_number"/>
    <xsl:text>&#xA;</xsl:text>
    <xsl:text>B </xsl:text>
    <xsl:value-of select="prepared_by"/>
    <xsl:text> </xsl:text>
    <xsl:value-of select="contact_number"/>
    <xsl:text>&#xA;</xsl:text>
    <xsl:for-each select="key('value-by-firm', firm_number)">
      <xsl:text>C </xsl:text>
      <xsl:value-of select="trade_date"/>
      <xsl:text> </xsl:text>
      <xsl:value-of select="symbol"/>
      <xsl:text>&#xA;</xsl:text>
   </xsl:for-each>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

多分それをする別の方法があります。前もって感謝します。

4

2 に答える 2

1

「間違った」ものをグループ化し、グループを誤って使用しています。

  • Record要素をグループ化しようとしています。エルゴ、それらはあなたと一致する必要がありますxsl:keyuse=...属性は会社名を参照する必要があります)
  • グループ化のトリックは、各グループを1回だけ処理することで機能します。各キーを明示的に処理することはできないため、代わりにすべての値を処理し、グループの最初のxsl:key値を除くすべてを無視して、グループ全体の処理をそこで実行します。つまり、foreachはdoesと同じ要素を選択し、ノードテストalaを追加する必要があります。ここでは、 andの部分を忘れています。xsl:key[count(. | reference-to-group[1]) = 1][1]= 1

T次に、修正されたXSLTファイル(フィールドルックアップもわずかに変更され、計算を追加しなかったことに注意してください。

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="value-by-firm" match="/Report/RecordValues/Record" use="FieldValue[@fieldName='firm_number']/@fieldValue"/>
  <xsl:template match="/">
    <xsl:for-each select="/Report/RecordValues/Record[count(. | key('value-by-firm', FieldValue[@fieldName='firm_number']/@fieldValue)[1]) = 1]">
      <xsl:text>A </xsl:text>
      <xsl:value-of select="FieldValue[@fieldName='firm_name']/@fieldValue"/>
      <xsl:text> </xsl:text>
      <xsl:value-of select="FieldValue[@fieldName='firm_number']/@fieldValue"/>
      <xsl:text>&#xA;</xsl:text>
      <xsl:text>B </xsl:text>
      <xsl:value-of select="FieldValue[@fieldName='prepared_by']/@fieldValue"/>
      <xsl:text> </xsl:text>
      <xsl:value-of select="FieldValue[@fieldName='contact_number']/@fieldValue"/>
      <xsl:text>&#xA;</xsl:text>
      <xsl:for-each select="key('value-by-firm', FieldValue[@fieldName='firm_number']/@fieldValue)">
        <xsl:text>C </xsl:text>
        <xsl:value-of select="FieldValue[@fieldName='trade_date']/@fieldValue"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="FieldValue[@fieldName='symbol']/@fieldValue"/>
        <xsl:text>&#xA;</xsl:text>
      </xsl:for-each>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

編集:最後の注意:このデータスキーマを前提として行っていることは、XSLTの長所の1つではありません。はるかにクリーンなスキーマに自然に変換できるデータ構造があるようです(たとえば、名前と値のペアがXMLの自然な名前と値のペア、つまり属性で表されます)。あるいは、それを「実際の」プログラミング言語(このデータがほぼ確実に由来する場所)にインポートすることもできます。この言語では、FieldValue要素やfieldNameおよびfieldValue属性などのすべての要素が表現されていません。基本的に; これはXML+XSLTで可能ですが、より自然な表現で表現し、より自然なツールで処理する場合よりも、より複雑で脆弱なソリューションになります。

于 2010-12-13T19:30:39.443 に答える
1

このスタイルシート:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:key name="kRecordByFirmAndContact" match="Record"
             use="concat(FieldValue[@fieldName='firm_number']
                            /@fieldValue,
                         '+',
                         FieldValue[@fieldName='contact_number']
                            /@fieldValue)"/>
    <xsl:template
         match="Record
                   [count(.|key('kRecordByFirmAndContact',
                                concat(FieldValue
                                          [@fieldName='firm_number']
                                          /@fieldValue,
                                       '+',
                                       FieldValue
                                          [@fieldName='contact_number']
                                          /@fieldValue))[1])
                    = 1 ]">
        <xsl:variable name="vRecords"
                      select="key('kRecordByFirmAndContact',
                                  concat(FieldValue
                                            [@fieldName='firm_number']
                                            /@fieldValue,
                                         '+',
                                         FieldValue
                                            [@fieldName='contact_number']
                                            /@fieldValue))"/>
        <xsl:value-of select="concat('A ',
                                     *[@fieldName='firm_name']
                                      /@fieldValue,
                                     ' ',
                                     *[@fieldName='firm_number']
                                      /@fieldValue,
                                     '&#xA;',
                                     'B ',
                                     *[@fieldName='prepared_by']
                                      /@fieldValue,
                                     ' ',
                                     *[@fieldName='contact_number']
                                      /@fieldValue,
                                     '&#xA;')"/>
        <xsl:apply-templates select="$vRecords" mode="RecordC"/>
        <xsl:value-of select="concat('T ',count($vRecords) + 2,'&#xA;')"/>
    </xsl:template>
    <xsl:template match="Record" mode="RecordC">
        <xsl:value-of select="concat('C ',
                                     *[@fieldName='trade_date']
                                      /@fieldValue,
                                     ' ',
                                     *[@fieldName='symbol']
                                      /@fieldValue,
                                     '&#xA;')"/>
    </xsl:template>
</xsl:stylesheet>

出力:

A Firm_1 11
B PARKER 123456789
C 2010-10-17 ADM
C 2010-10-16 ACW
T 4
A Firm_2 12
B EDWARDS 123456780
C 2010-10-19 ADS
T 3

:ご覧のとおり、これは複雑ではありませんが、スキーマによってコードが非常に冗長になります...これはデータダンプのM$XML形式のように見えます。

于 2010-12-13T20:48:15.487 に答える