1

申し訳ありませんが、以下の問題を更新しました。

最初は本当に単純に見えたのに、後で本当に複雑なものに変わりました。誰でも私を助けることができますか?

この XML が必要です

<?xml version="1.0" encoding="UTF-8"?>


<RecordSet>
    <Data image="h1.gif" description="a"/>
    <Data image="" description="asdf" />
    <Data image="" description="bsdf"/>
    <Data image="" description="csdf"/>
    <Data image="h2.gif" description="b"/>
    <Data image="" description="dsdf"/>
    <Data image="" description="esdf"/>
    <Data image="h3.gif" description="c"/>
    <Data image="" description="sdff"/>
</RecordSet>

これに変換

 <RecordSet>
    <MenuHeader image="h1.gif">
        <Menu description="a"/>
        <Menu description="b"/>
        <Menu description="c"/>
    </MenuHeader>
    <MenuHeader image="h2.gif">
        <Menu description="d"/>
        <Menu description="e"/>
    </MenuHeader>
    <MenuHeader image="h3.gif">
        <Menu description="f"/>
    </MenuHeader>
</RecordSet>

使用されるスタイルシート

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

<xsl:output indent="yes"/>

<xsl:template match="RecordSet">
 <RecordSet>
  <xsl:for-each select="Data[not(@image='')]">
   <MenuHeader image="{@image}">
    <xsl:copy-of select="key('d',@image)"/>
   </MenuHeader>
  </xsl:for-each>
 </RecordSet>
</xsl:template>

<xsl:key name="d"
     match="Data[@description]" 
     use="preceding-sibling::Data[@image][1]/@image"/>

</xsl:stylesheet>

実際の出力:

<?xml version="1.0" encoding="UTF-8"?>
<RecordSet>
    <MenuHeader image="h1.gif">
        <Data image="" description="asdf"/>
    </MenuHeader>
    <MenuHeader image="h2.gif">
        <Data image="" description="dsdf"/>
    </MenuHeader>
    <MenuHeader image="h3.gif">
        <Data image="" description="sdff"/>
    </MenuHeader>
</RecordSet>

更新: 値を持つイメージ属性を持つデータ ノードは、MenuHeader として設定する必要があります。どんな助けも本当に大きな助けになります。

4

4 に答える 4

1

受け入れられた回答は、元の投稿で希望する出力を生成しません。このわずかに変更されたバージョン (まだ XSLT 1.0) でうまくいくはずです。

別の XSLT 1.0 の代替案を次に示します。

この XSLT の場合:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="no" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key
     name="kDataByPrecedingImage"
     match="Data[@image = '']"
     use="generate-id(preceding-sibling::*[@image != ''][1])"/>

  <xsl:template match="RecordSet">
    <RecordSet>
      <xsl:apply-templates select="*[@image != '']"/>
    </RecordSet>
  </xsl:template>

  <xsl:template match="Data">
    <MenuHeader image="{@image}">
      <xsl:apply-templates
        select="key('kDataByPrecedingImage', generate-id())"
        mode="children"/>
    </MenuHeader>
  </xsl:template>

  <xsl:template match="Data" mode="children">
    <Menu description="{@description}"/>
  </xsl:template>

</xsl:stylesheet>

...指定された XML に対して適用されます。

<?xml version="1.0" encoding="UTF-8"?>
<RecordSet>
  <Data image="h1.gif" description="a"/>
  <Data image="" description="asdf"/>
  <Data image="" description="bsdf"/>
  <Data image="" description="csdf"/>
  <Data image="h2.gif" description="b"/>
  <Data image="" description="dsdf"/>
  <Data image="" description="esdf"/>
  <Data image="h3.gif" description="c"/>
  <Data image="" description="sdff"/>
</RecordSet>

...目的の結果が生成されます。

<?xml version="1.0" encoding="UTF-8"?>
<RecordSet>
  <MenuHeader image="h1.gif">
    <Menu description="asdf"/>
    <Menu description="bsdf"/>
    <Menu description="csdf"/>
  </MenuHeader>
  <MenuHeader image="h2.gif">
    <Menu description="dsdf"/>
    <Menu description="esdf"/>
  </MenuHeader>
  <MenuHeader image="h3.gif">
    <Menu description="sdff"/>
  </MenuHeader>
</RecordSet>
于 2013-11-10T06:01:22.720 に答える
1

「while」ループを近似するために末尾再帰を使用する別のアプローチを次に示します。

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

  <xsl:template match="/RecordSet">
    <RecordSet>
      <xsl:apply-templates select="Data[@image != '']"/>
    </RecordSet>
  </xsl:template>

  <xsl:template match="Data[@image != '']">
    <MenuHeader image="{@image}">
      <xsl:apply-templates select="following-sibling::Data[1][@image='']" />
    </MenuHeader>
  </xsl:template>

  <xsl:template match="Data">
    <Menu description="{@description}"/>
    <xsl:apply-templates select="following-sibling::Data[1][@image='']" />
  </xsl:template>
</xsl:stylesheet>

ここでの秘訣は、テンプレートを生成するMenuHeaderテンプレートが、それに続く最初の (もしあれば) 非画像Data要素だけにテンプレートを適用することです。imageそのテンプレートは、再帰が自動的に停止する次のテンプレートに があるポイントに到達するまで、次のテンプレートなどを再帰的に消費します。

于 2013-11-09T10:07:48.360 に答える
1

これは XSLT 2 の方が簡単ですが、昔から XSLT 1 を使用しています。

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

<xsl:output indent="yes"/>

<xsl:template match="RecordSet">
 <RecordSet>
  <xsl:for-each select="Data[string(@image)]">
   <MenuHeader image="{@image}">
    <xsl:for-each select="key('d',@image)">
     <Menu>
      <xsl:copy-of select="@description"/>
     </Menu>
    </xsl:for-each>
   </MenuHeader>
  </xsl:for-each>
 </RecordSet>
</xsl:template>

<xsl:key name="d"
     match="Data[not(string(@image))][@description]" 
     use="preceding-sibling::Data[string(@image)][1]/@image"/>

</xsl:stylesheet>

プロデュース

<?xml version="1.0" encoding="utf-8"?>
<RecordSet>
   <MenuHeader image="h1.gif">
      <Menu description="asdf"/>
      <Menu description="bsdf"/>
      <Menu description="csdf"/>
   </MenuHeader>
   <MenuHeader image="h2.gif">
      <Menu description="dsdf"/>
      <Menu description="esdf"/>
   </MenuHeader>
   <MenuHeader image="h3.gif">
      <Menu description="sdff"/>
   </MenuHeader>
</RecordSet>

image=""画像属性がないのではなく、必要な質問の更新版に注意してください。テストはstring(@image)単に@image.

于 2013-11-08T18:47:20.250 に答える
1

2.0 オプション、プッシュ式。

XML 入力

<RecordSet>
    <Data image="h1.gif"/>
    <Data description="a"/>
    <Data description="b"/>
    <Data description="c"/>
    <Data image="h2.gif"/>
    <Data description="d"/>
    <Data description="e"/>
    <Data image="h3.gif"/>
    <Data description="f"/>
</RecordSet>

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/*">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:for-each-group select="Data" group-starting-with="Data[@image]">
                <MenuHeader image="{@image}">
                    <xsl:apply-templates select="current-group()[not(@image)]"/>
                </MenuHeader>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Data">
        <Menu>
            <xsl:apply-templates select="@*|node()"/>
        </Menu>
    </xsl:template>

</xsl:stylesheet>

出力

<RecordSet>
   <MenuHeader image="h1.gif">
      <Menu description="a"/>
      <Menu description="b"/>
      <Menu description="c"/>
   </MenuHeader>
   <MenuHeader image="h2.gif">
      <Menu description="d"/>
      <Menu description="e"/>
   </MenuHeader>
   <MenuHeader image="h3.gif">
      <Menu description="f"/>
   </MenuHeader>
</RecordSet>
于 2013-11-08T22:16:59.737 に答える