1

重複の可能性:
xslt を使用して入力 xml を他の XML に変換する

私は XSLT の初心者です。興味のあるタスクのコードをいくつか見て、いくつかのロジックを構築しましたが、目的の出力を得ることができませんでした。助けていただければ幸いです。

入力 XML:

<?xml version="1.0" encoding="UTF-8"?>
<t>
<Data>
    <CD>
        <Artist>xxx.yyy</Artist>
        <song>abc</song>
    </CD>
    <CD>
        <Artist>xxx.zzz</Artist>
        <song>cba</song>
    </CD>
    <CD>
        <Artist>aaa.kkk</Artist>
        <song>123</song>
    </CD>
    <CD>
        <Artist>aaa.lll</Artist>
        <song>456</song>
    </CD>
    <CD>
        <Artist>ddd</Artist>
        <song>1234</song>
    </CD>
</Data>
<Music>
    <music_no>E123</music_no>
    <music_type>outdoor</music_type>
    <Artist>bat.ball</Artist>
    <value>0000</value>
</Music>
<Music>
    <music_no>E123</music_no>
    <music_type>outdoor</music_type>
    <Artist>bat.stone</Artist>
    <value>0001</value>
</Music>
<Music>
    <music_no>E111</music_no>
    <music_type>outdoor</music_type>
    <Artist>board.coins</Artist>
    <value>0002</value>
</Music>
<Music>
    <music_no>E111</music_no>
    <music_type>outdoor</music_type>
    <Artist>board.ball</Artist>
    <value>0003</value>
</Music>
<Music>
    <music_no>E001</music_no>
    <music_type>indoor</music_type>
    <Artist>bat.ball</Artist>
    <value>8888</value>
</Music>
<Music>
    <music_no>E001</music_no>
    <music_type>indoor</music_type>
    <Artist>bat.stone</Artist>
    <value>9999</value>
</Music>
<Music>
    <music_no>E111</music_no>
    <music_type>indoor</music_type>
    <Artist>board.coins</Artist>
    <value>0001</value>
</Music>
<Music>
    <music_no>E111</music_no>
    <music_type>indoor</music_type>
    <Artist>bat</Artist>
    <value>0001</value>
</Music>
</t>

期待される出力:

<?xml version="1.0" encoding="UTF-8"?>
<version_3>
<information>
    <xxx>
        <yyy>abc</yyy>
        <zzz>cba</zzz>
    </xxx>
    <aaa>
        <kkk>123</kkk>
        <lll>456</lll>
    </aaa>
    <ddd>1234</ddd>
</information>
<information>
    <bat>
        <ball>0000</ball>
        <stone>0001</stone>
    </bat>
    <board>
        <coins>0002</coins>
        <ball>0003</ball>
    </board>
    <bat>
        <ball>8888</ball>
        <stone>9999</stone>
    </bat>
    <board>
        <coins>0001</coins>
    </board>
</information>
<information>
    <bat>0001</bat>
</information>
 </version_3>

編集された期待される出力:

Expected Output:

<?xml version="1.0" encoding="UTF-8"?>
<version_3>
<information>
    <xxx>
        <yyy>abc</yyy>
        <zzz>cba</zzz>
    </xxx>
    <aaa>
        <kkk>123</kkk>
        <lll>456</lll>
    </aaa>
    <ddd>1234</ddd>
</information>
<information>
    <bat>
        <ball>0000</ball>
        <stone>0001</stone>
    </bat>
</information>
<information>
    <board>
        <coins>0002</coins>
        <ball>0003</ball>
    </board>
    <board>
        <coins>0001</coins>
                          <bat>0001</bat>
    </board>
</information>
<information>
    <bat>
        <ball>8888</ball>
        <stone>9999</stone>
    </bat>
      </information>
   </version_3>

上記の入力 XML では、"音楽" と同様に、"CD" 要素とその値に気付くことができます。次のような出力を得たいのですが、

「CD」の出力例:

<information>
    <xxx>
        <yyy>abc</yyy>
        <zzz>cba</zzz>
    </xxx>
    <aaa>
        <kkk>123</kkk>
        <lll>456</lll>
    </aaa>
    <ddd>1234</ddd>
</information>

これは Muenchian Grouping によってある程度達成できました。しかし、

次の要素「Music」にはサブ要素があり、最初の 2 つの要素「music_no」と「music_type」が一致し、「Artist」の値をグループ化する必要があります。一致しない場合は、個別にグループ化する必要があります。

音楽のサンプル o/p:

<information>
    <bat>
        <ball>0000</ball>
        <stone>0001</stone>
    </bat>
    <board>
        <coins>0002</coins>
        <ball>0003</ball>
    </board>
    <bat>
        <ball>8888</ball>
        <stone>9999</stone>
    </bat>
    <board>
        <coins>0001</coins>
    </board>
</information>
<information>
    <bat>0001</bat>
</information>

2 番目の部分は反復処理が少し難しいため、達成できませんでした。助けていただければ幸いです。

注: アーティストの値が対応するノードと同じであるが「.」がない場合、「Music」要素の場合。次に、その値は「情報」の外部にある個別にグループ化する必要があり、新しい「情報」を持つ必要があります

私が取り組んだ私のコード:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"            xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:key name="kBychildName" match="CD" use="name(Artist/*[1])"/>
<xsl:key name="kByAttribs" match="Artist" use="concat(../@music_no, '+', ../@music_type)"/>
<xsl:key name="kChildByAttribsAndArtist" match="Artist/*" use="concat(../../@music_no, '+', ../../@music_type, '+', name())"/>
<xsl:template match="/">
    <version_3>
        <information>
            <xsl:variable name="var1">
                <xsl:apply-templates/>
            </xsl:variable>
            <xsl:apply-templates mode="pass2" select="ext:node-set($var1)/* [generate-id()=generate-id(key('kBychildName',name(Artist/*[1]))[1]) or not(Artist/*)]"/>
        </information>
        <information>
            <xsl:variable name="var2">
                <xsl:apply-templates/>
            </xsl:variable>
            <xsl:apply-templates mode="pass3" select="ext:node-set($var2)/*/* [generate-id() = generate-id(key('kByAttribs', concat(../@music_no, '+', ../@music_type) ) [1])] "/>
        </information>
    </version_3>
    <!--xsl:copy-of select="//msg_debug"/-->
</xsl:template>
<xsl:template match="CD[contains(Artist,'.')]">
    <CD>
        <Artist>
            <xsl:element name="{substring-before(Artist, '.')}">
                <xsl:element name="{substring-after(Artist, '.')}">
                    <xsl:value-of select="song"/>
                </xsl:element>
            </xsl:element>
        </Artist>
    </CD>
</xsl:template>
<xsl:template match="CD">
    <CD>
        <Artist>
            <xsl:element name="{Artist}">
                <xsl:value-of select="song"/>
            </xsl:element>
        </Artist>
    </CD>
</xsl:template>
<xsl:template match="CD" mode="pass2">
<xsl:apply-templates select="*/*[1]" mode="pass2"/>
</xsl:template>
<xsl:template match="Artist/*" mode="pass2">
    <xsl:copy>
        <xsl:copy-of select="self::*[not(*)]/text()|key('kBychildName', name())/*/*/*"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Music[contains(Artist, '.')]">
    <Music music_no="{music_no}" music_type="{music_type}">
        <Artist>
            <xsl:element name="{substring-before(Artist, '.')}">
                <xsl:element name="{substring-after(Artist, '.')}">
                    <xsl:value-of select="value"/>
                </xsl:element>
            </xsl:element>
        </Artist>
    </Music>
</xsl:template>
<xsl:template match="Music">
    <Music music_no="{music_no}" music_type="{music_type}">
        <Artist>
            <xsl:element name="{Artist}">
                <xsl:value-of select="value"/>
            </xsl:element>
        </Artist>
    </Music>
</xsl:template>
<xsl:template match="Artist" mode="pass3">
    <!--Artist-->
    <xsl:apply-templates mode="pass3" select="*[generate-id() =generate-id(key('kChildByAttribsAndArtist', concat(../../@music_no, '+', ../../@music_type,'+', name()))[1] ) ]"/>
    <xsl:copy-of select="key('kByAttribs',concat(../@music_no, '+', ../@music_type) )/*[not(*)] "/>
    <!--/Artist-->
</xsl:template>
<xsl:template match="Artist/*" mode="pass3">
    <xsl:element name="{name()}">
        <xsl:copy-of select="key('kChildByAttribsAndArtist', concat(../../@music_no, '+', ../../@music_type, '+', name()) )/* "/>
    </xsl:element>
</xsl:template>
 </xsl:stylesheet>

問題が難しい場合は、もう一度説明していただければ幸いです。XSLT の初心者として、あなたが私を助けてくれることを願っています。

4

1 に答える 1

1

簡単な質問には、簡単な答えが必要です。この XSLT 1.0 スタイルシートは ...

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

<xsl:key name="artist-group" match="CD|Music" use="
      concat( substring-before(Artist,'.'),'|',music_no,'|',music_type)"/>

<xsl:template match="/">
  <version_3>

   <information> 
     <xsl:apply-templates select="t/Data/CD
     [generate-id(.) = generate-id( key('artist-group',
       concat( substring-before(Artist,'.'),'||'))[1])]
     [substring-before(Artist,'.')]" />
     <xsl:apply-templates select="key('artist-group','||')/self::CD" />
   </information> 

   <information> 
     <xsl:apply-templates select="t/Music
     [generate-id(.) = generate-id( key('artist-group',
       concat( substring-before(Artist,'.'),'|',music_no,'|',music_type))[1])]
     [substring-before(Artist,'.')]" />
   </information> 

   <information> 
     <xsl:apply-templates select="t/Music[substring-before(Artist,'.') = '']" />
   </information> 

  </version_3>
</xsl:template>

<xsl:template match="CD[ substring-before(Artist,'.') != ''] |
                  Music[ substring-before(Artist,'.') != '']">
 <xsl:element name="{substring-before(Artist,'.')}">
  <xsl:for-each select="key('artist-group',
     concat( substring-before(Artist,'.'),'|',music_no,'|',music_type))" >
   <xsl:element name="{substring-after(Artist,'.')}">
    <xsl:value-of select="song|value" /> 
   </xsl:element>  
  </xsl:for-each> 
 </xsl:element>
</xsl:template>


<xsl:template match="CD[ substring-before(Artist,'.')  = ''] |
                  Music[ substring-before(Artist,'.')  = '']">
 <xsl:element name="{Artist}">
  <xsl:value-of select="song|value" /> 
 </xsl:element>
</xsl:template>

</xsl:stylesheet>

...サンプル入力に適用すると、必要な期待される出力が生成されます。

説明

音楽要素と CD 要素の両方をグループ化するために 1 つのキーが使用されます。音楽の場合、music_no と music_type にさらに分割されます。最初の出力情報ノードは、CD 要素の muenchian グループ化から派生します。最初の情報ノード内の孤立したアーティストは、命令によって生成されます。

共通のペア CD|Music テンプレートは、すべてのグループ化アーティスト ノードおよび孤児アーティスト ノードの生成に使用されます。述語 [substring-before(Artist,'.')!=''] を持つテンプレート ペアの最初のものは、グループ化されたアーティストに使用され、もう 1 つは孤立したアーティストに使用されます。

2 番目の情報ノードの生成は、入力音楽ノードに基づいており、孤立したアーティストを除外する点を除いて、最初のノードと同じです。

3 番目の情報ノードの生成は、孤立した音楽ノードから派生します。

「孤立した」とは、Artist 値にドット文字が含まれていないノードを意味します。

于 2012-07-09T08:24:58.890 に答える