2011-07-11 1 views
3

にフラットな構造を変換ここでソースXMLです:XSLTは、アレイ

<customers> 
    <firstname1>Sean</firstname1> 
    <lastname1>Killer</lastname1> 
    <sex1>M</sex1> 
    <firstname2>Frank</firstname2> 
    <lastname2>Woods</lastname2> 
    <sex2>M</sex2> 
    <firstname3>Jennifer</firstname3> 
    <lastname3>Lee</lastname3> 
    <sex3>F</sex3> 
</customers> 

私はこれに変換できますか?

コメントを1として
<MyCustomers> 
    <Customer> 
     <Name> Sean Killer</Name> 
     <Sex>M</Sex> 
    </Customer> 
    <Customer> 
     <Name> Frank Woods</Name> 
     <Sex>M</Sex> 
    </Customer> 
    <Customer> 
     <Name>Jennifer Lee</Name> 
     <Sex>F</Sex> 
    </Customer> 
</MyCustomers> 
+0

「コード」のマークアップを使用して投稿を書き留めてください。 –

+0

良い質問、+1。 XSLT 1.0を使用する最も一般的で柔軟なソリューションについては、私の答えをご覧ください。一番上の要素の子が任意の方法で再シャッフルされても、望みの結果が得られます。 :) –

+0

また、説明が追加されました。 –

答えて

4

要素が結果的に受注していなかった場合は何?あなたは要素のIDを取得するためにtranslate()を使用して、concat()を使用して構築された正しい名前で対応する要素を検索することができます(XSLT 1.0と仮定)。この場合

。私は最終的には、現在のfirstnameの前の要素をキャッチすることを確認する(parent::の略)../following-sibling::軸を変更します。

<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="customers"> 
     <MyCustomers> 
      <xsl:apply-templates select="*[starts-with(name(),'firstname')]"/> 
     </MyCustomers> 
    </xsl:template> 

    <xsl:template match="*[starts-with(name(),'firstname')]"> 
     <xsl:variable name="id" select="translate(name(),'firstname','')"/> 

     <Customer> 
      <Name><xsl:value-of select="concat(.,' ', 
        ../*[name()=concat('lastname',$id)])"/></Name> 
      <Sex><xsl:value-of select="../*[name()=concat('sex',$id)]"/></Sex> 
     </Customer> 
    </xsl:template> 

</xsl:stylesheet> 

廃止された解答の質問に示すように、微細加工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:template match="customers"> 
     <MyCustomers> 
      <xsl:apply-templates select="*[starts-with(name(),'firstname')]"/> 
     </MyCustomers> 
    </xsl:template> 

    <xsl:template match="*[starts-with(name(),'firstname')]"> 
     <Customer> 
      <Name><xsl:value-of select="concat(.,' ', 
        following-sibling::*[1] 
        [starts-with(name(),'lastname')])"/></Name> 
      <Sex><xsl:value-of select="following-sibling::*[2] 
        [starts-with(name(),'sex')]"/></Sex> 
     </Customer> 
    </xsl:template> 

</xsl:stylesheet> 

説明

あなたはあなたのためのXML入力のタグの悲しい名前のXPath 1.0の機能starts-with()を必要としています。 following-sibling::軸を使用して、名前がfirstnameで始まる任意の要素の必須の次の兄弟タグを取得できます。

+0

あなたの答えをありがとう。しかし、どのような要素が結果的に受注していない場合について:ショーン \t \t フランク \t キラー \t M \t ウッズ \t ジェニファー \t リー \t F \t M sean

+0

要素は、結果として順になっていない場合は、お使いのサンプル入力を適切にあなたの本当のXMLを反映するものではありません。しかし、要素が結果的な順序でない場合、たとえば、特定の 'sex'タグが特定の' firstname'に属していることをどのように知ることができますか?もっときれいになれますか? –

+0

ここで、要素名に追加された整数に依存していますか? –

0

ここで彼らは順番になっていない場合でも、あなたが探しているの出力が得られますXSLT 2.0スタイルシートです。また、 "firstname"要素名によってソートされます。

サンプル(異なる順序を示すまで混合)XML入力:サクソン-HE 9で試験

<customers> 
    <lastname1>Killer</lastname1> 
    <sex3>F</sex3> 
    <firstname2>Frank</firstname2> 
    <firstname1>Sean</firstname1> 
    <lastname2>Woods</lastname2> 
    <sex2>M</sex2> 
    <firstname3>Jennifer</firstname3> 
    <sex1>M</sex1> 
    <lastname3>Lee</lastname3> 
</customers> 

XSLT 2.0スタイルシート(。3):

<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:choose> 
     <xsl:when test="name()[starts-with(.,'firstname')]"> 
     <xsl:variable name="suffix" select="substring(name(),10)"></xsl:variable> 
     <xsl:message><xsl:value-of select="$suffix"/></xsl:message> 
     <customer> 
      <Name> 
      <xsl:value-of select="concat(.,' ',/customers/*[starts-with(name(),'lastname')][ends-with(name(),$suffix)])"/> 
      </Name> 
      <Sex> 
      <xsl:value-of select="/customers/*[starts-with(name(),'sex')][ends-with(name(),$suffix)]"/> 
      </Sex> 
     </customer> 
     </xsl:when> 
     <xsl:when test="name()='customers'"> 
     <MyCustomers> 
      <xsl:apply-templates> 
      <xsl:sort select="name()[starts-with(.,'firstname')]"></xsl:sort> 
      </xsl:apply-templates> 
     </MyCustomers> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:apply-templates select="node()|@*"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 

</xsl:stylesheet> 

出力:

<MyCustomers> 
    <customer> 
     <Name>Sean Killer</Name> 
     <Sex>M</Sex> 
    </customer> 
    <customer> 
     <Name>Frank Woods</Name> 
     <Sex>M</Sex> 
    </customer> 
    <customer> 
     <Name>Jennifer Lee</Name> 
     <Sex>F</Sex> 
    </customer> 
</MyCustomers> 
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:variable name="vNumCustomers" 
     select="count(/*/*) div 3"/> 

<xsl:template match="/*"> 
    <MyCustomers> 
     <xsl:for-each select= 
      "*[not(position() > $vNumCustomers)]"> 
     <xsl:variable name="vNum" select="position()"/> 

     <Customer> 
      <Name> 
      <xsl:value-of select= 
      "concat(/*/*[name()=concat('firstname',$vNum)], 
        ' ', 
        /*/*[name()=concat('lastname',$vNum)] 
        ) 
      "/> 
      </Name> 
      <Sex> 
      <xsl:value-of select= 
      "/*/*[name()=concat('sex',$vNum)] 
      "/> 
      </Sex> 
     </Customer> 
     </xsl:for-each> 
    </MyCustomers> 
</xsl:template> 
</xsl:stylesheet> 

このXMLドキュメントに適用された場合(提供される一つの任意再シャッフリング):希望、正しい結果がを生成さ

<customers> 
    <sex1>M</sex1> 
    <lastname2>Woods</lastname2> 
    <lastname1>Killer</lastname1> 
    <sex2>M</sex2> 
    <firstname3>Jennifer</firstname3> 
    <firstname2>Frank</firstname2> 
    <lastname3>Lee</lastname3> 
    <firstname1>Sean</firstname1> 
    <sex3>F</sex3> 
</customers> 

<MyCustomers> 
    <Customer> 
     <Name>Sean Killer</Name> 
     <Sex>M</Sex> 
    </Customer> 
    <Customer> 
     <Name>Frank Woods</Name> 
     <Sex>M</Sex> 
    </Customer> 
    <Customer> 
     <Name>Jennifer Lee</Name> 
     <Sex>F</Sex> 
    </Customer> 
</MyCustomers> 

説明:我々は、計算

  1. データが提示される顧客の数。変数$vNumCustomersはこのデータを保持します。

  2. 各顧客{i}(i = 1〜$vNumCustomers)に対して、対応する<Customer{i}>要素を作成します。再帰の使用を避けるため、ここではthe Piez methodを使用します。

+0

私は "count(/ */*)div 3"の考え方が好きですが、ソースXMLに他の無関係の要素が含まれているとうまくいかない場合があります: 2011-07-11...... sean

+0

@sean:もちろんです。はるかに一般的な解決策がありますが、私はそれを私の答えに合わせるための自由な時間を見つけるだけでよいのです。私の現在の答えは余分な5分で生成されました。 –

+0

私はそれを感謝します。ところで、あなたはどちらの方が好きですか?これは、それぞれのループソリューションかテンプレートマッチソリューションですか? – sean