2009-04-23 21 views
1

私はこのようなXMLを持っている、ノードをマージ:XSLT:その後、ソート

<node id="1"> 
    <data alias="Show">ShowName1</data> 
    <data alias="Dates">21/04/2009,23/04/2009,27/04/2009,</data> 
</node> 

<node id="2"> 
    <data alias="Show">ShowName2</data> 
    <data alias="Dates">22/04/2009,25/04/2009,29/04/2009,</data> 
</node> 

これは、Xノードの数、ショーの名前でそれぞれ、およびカンマ区切りショーの日付の文字列を持っています。 ショーの日程をトークン化することはできますが、すべてのショーのすべてのショーの日付をソートしたリストを日付順に並べ替えることができます。このように:

<shows> 
    <show> 
     <name>ShowName1</name> 
     <date>21/04/2009</date> 
    </show> 
    <show> 
     <name>ShowName2</name> 
     <date>22/04/2009</date> 
    </show> 
    <show> 
     <name>ShowName1</name> 
     <date>23/04/2009</date> 
    </show> 
    <show> 
     <name>ShowName2</name> 
     <date>25/04/2009</date> 
    </show> 
    <show> 
     <name>ShowName1</name> 
     <date>27/04/2009</date> 
    </show> 
    <show> 
     <name>ShowName2</name> 
     <date>29/04/2009</date> 
    </show> 
</shows> 

これはまったく可能ですか?ソート力学:だけは、プロセステンプレートは、内部XSLを使用することができますので、ノードセットとして見られることを新たに作成したショーの要素を必要とする変換を使用してこれを行うには

+0

XSLT 1.0または2.0? – Tomalak

答えて

2

XSL Transformations (XSLT) Version 1.0 specには、自己作成要素をノード集合に変換するメソッドはありません。ただし、MSXML parser(3.0以上)には、その機能を提供する拡張機能があります。また、exslt extensionがあります。これは、Firefoxの新しいバージョンのサポートで、この変数をノードセットに動的にスワップすることができると思います。しかし、とにかく、MSXMLパーサーを使って正しく動作するスタイルシートがあります。

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" 
       xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> 
    <xsl:output method="xml"/> 

    <xsl:template match="/"> 
    <xsl:variable name="shows"> 
     <xsl:apply-templates select="//data[@alias='Dates']"/> 
    </xsl:variable> 
    <shows> 
     <xsl:apply-templates select="msxsl:node-set($shows)//show"> 
     <xsl:sort select="substring(date, 7, 4)"/><!-- year --> 
     <xsl:sort select="substring(date, 4, 2)"/><!-- month --> 
     <xsl:sort select="substring(date, 1, 2)"/><!-- day --> 
     </xsl:apply-templates> 
    </shows> 
    </xsl:template> 

    <xsl:template match="show"> 
    <xsl:copy-of select="."/> 
    </xsl:template> 

    <xsl:template match="data[@alias='Dates']"> 
    <xsl:call-template name="eachDate"> 
     <xsl:with-param name="node" select=".."/> 
     <xsl:with-param name="dates" select="."/> 
    </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="eachDate"> 
    <xsl:param name="node" select="."/> 
    <xsl:param name="dates" select="''"/> 
    <xsl:if test="string-length($dates)"> 
     <show> 
     <name><xsl:value-of select="$node/data[@alias='Show']/text()"/></name> 
     <date><xsl:value-of select="substring-before($dates, ',')"/></date> 
     </show> 
     <xsl:call-template name="eachDate"> 
     <xsl:with-param name="node" select="$node"/> 
     <xsl:with-param name="dates" select="substring-after($dates, ',')"/> 
     </xsl:call-template> 
    </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 
+0

これは日付の並べ替えを間違ってしまいます。個々の日付で並べ替える必要があります。*と*は、ソートに適していない "DDMMYYYY"ではないので、ソートする前にトークン化して "YYYYMMDD"にする必要があります。 – Tomalak

+0

良いキャッチは、提供された少量のデータに対して十分にうまく機能しました。 あなたがしなければならないことは、部分文字列(データ、7,4)などでソートすることです。私のxsl:sortを更新して、意味を表示します。トークン化する必要はなく、テキスト値をまったく混乱させる必要はありません。 –

+0

ありがとうございました。君たちは最高です!ちょうど私が必要とした問題、そして解決された問題(そして、整形式XMLを提供していないDimitreへの私の謝罪は、再び起こりません:)) – Arild

1

入力XMLがかなり悪い形になっているので、私たちはあなたが望むものを得るためにいくつかのフープを飛ばしなければなりません。

ミスター・ラッキーは既に彼の答えで概説しているように、まずドキュメントをより有用な一時的なフォームに変換する必要があります。より有用な一時的フォームは、拡張関数によってノード集合に戻され、再び処理されて所望の結果が生成される。私は修正IDを使用します私の答えで

には、次の一時的なフォームを達成するための変換:

<root> 
    <node id="1"> 
    <data alias="Show">ShowName1</data> 
    <data alias="Dates"> 
     <date sort="20090421">21/04/2009</date> 
     <date sort="20090423">23/04/2009</date> 
     <date sort="20090427">27/04/2009</date> 
    </data> 
    </node> 
    <node id="2"> 
    <data alias="Show">ShowName2</data> 
    <data alias="Dates"> 
     <date sort="20090422">22/04/2009</date> 
     <date sort="20090425">25/04/2009</date> 
     <date sort="20090429">29/04/2009</date> 
    </data> 
    </node> 
</root> 

この入力を使用すると、ソートは<date>要素の@sort属性を使用して、簡単です。これはmsxsl.exe介して実行される

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
    exclude-result-prefixes="msxsl " 
> 
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" /> 

    <xsl:template match="/"> 
    <!-- prepare our temporary form (a "result tree fragment") --> 
    <xsl:variable name="rtf"> 
     <xsl:apply-templates mode="rtf" /> 
    </xsl:variable> 

    <!-- transform the result tree fragment back to a node-set --> 
    <xsl:variable name="doc" select="msxsl:node-set($rtf)" /> 

    <!-- transform the temporary node-set, sorted by date --> 
    <shows> 
     <xsl:apply-templates select="$doc//date"> 
     <xsl:sort select="@sort" /> 
     </xsl:apply-templates> 
    </shows> 
    </xsl:template> 

    <xsl:template match="date"> 
    <show show_id="{ancestor::node/@id}"> 
     <name><xsl:value-of select="../../data[@alias='Show'][1]/text()" /></name> 
     <date><xsl:value-of select="." /></date> 
    </show> 
    </xsl:template> 

    <!-- all following templates are for producing the temporary form only --> 

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

    <xsl:template match="data[@alias='Dates']" mode="rtf"> 
    <xsl:copy> 
     <!-- copy all attributes --> 
     <xsl:apply-templates select="@*" mode="rtf" /> 
     <!-- this produces the <date> elements --> 
     <xsl:call-template name="tokenize-datelist" /> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template name="tokenize-datelist"> 
    <xsl:param name="input" select="." /> 
    <xsl:param name="delim" select="','" /> 

    <xsl:variable name="temp" select="concat($input, $delim)" /> 
    <xsl:variable name="head" select="substring-before($temp, $delim)" /> 
    <xsl:variable name="tail" select="substring-after($input, $delim)" /> 

    <xsl:if test="$head != ''"> 
     <date> 
     <!-- this produces the @sort attribute --> 
     <xsl:call-template name="tokenize-date"> 
      <xsl:with-param name="input" select="$head" /> 
     </xsl:call-template> 
     <xsl:value-of select="$head" /> 
     </date> 
     <xsl:if test="$tail != ''" > 
     <xsl:call-template name="tokenize-datelist"> 
      <xsl:with-param name="input" select="$tail" /> 
      <xsl:with-param name="delim" select="$delim" /> 
     </xsl:call-template> 
     </xsl:if> 
    </xsl:if> 
    </xsl:template> 

    <xsl:template name="tokenize-date"> 
    <xsl:param name="input" select="''" /> 
    <xsl:param name="delim" select="'/'" /> 

    <xsl:variable name="dd" select="substring-before($input, $delim)" /> 
    <xsl:variable name="my" select="substring-after($input, $delim)" /> 
    <xsl:variable name="mm" select="substring-before($my, $delim)" /> 
    <xsl:variable name="yy" select="substring-after($my, $delim)" /> 

    <xsl:attribute name="sort"> 
     <xsl:value-of select="concat($yy, $mm, $dd)" /> 
    </xsl:attribute> 
    </xsl:template> 

</xsl:stylesheet> 

、XSLT 1.0プロセッサは、次のような出力が生成される:

<shows> 
    <show show_id="1"> 
    <name>ShowName1</name> 
    <date>21/04/2009</date> 
    </show> 
    <show show_id="2"> 
    <name>ShowName2</name> 
    <date>22/04/2009</date> 
    </show> 
    <show show_id="1"> 
    <name>ShowName1</name> 
    <date>23/04/2009</date> 
    </show> 
    <show show_id="2"> 
    <name>ShowName2</name> 
    <date>25/04/2009</date> 
    </show> 
    <show show_id="1"> 
    <name>ShowName1</name> 
    <date>27/04/2009</date> 
    </show> 
    <show show_id="2"> 
    <name>ShowName2</name> 
    <date>29/04/2009</date> 
    </show> 
</shows> 
1

I. AN XSLT 1.0溶液使用FXSL 1.xの

この変換

<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:import href="strSplit-to-Words.xsl"/> 

    <xsl:output indent="yes" omit-xml-declaration="yes"/> 

    <xsl:template match="/*"> 
     <xsl:variable name="vDates"> 
     <xsl:for-each select="node"> 
      <nodeData name="{data[@alias = 'Show']}"> 
       <xsl:call-template name="str-split-to-words"> 
        <xsl:with-param name="pStr" select="data[@alias = 'Dates']"/> 
        <xsl:with-param name="pDelimiters" 
            select="','"/> 
       </xsl:call-template> 
      </nodeData> 
     </xsl:for-each> 
     </xsl:variable> 

     <xsl:apply-templates select="ext:node-set($vDates)/*/*[text()]"> 
     <xsl:sort data-type="number" select="substring(.,7)"/> 
     <xsl:sort data-type="number" select="substring(.,4,2)"/> 
     <xsl:sort data-type="number" select="substring(.,1,2)"/> 
     </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="word"> 
     <show> 
     <name> 
      <xsl:value-of select="../@name"/> 
     </name> 
      <date> 
      <xsl:value-of select="."/> 
      </date> 
     </show> 
    </xsl:template> 
</xsl:stylesheet> 

提供された "XML文書"に適用され、整形式に修正された場合(いつ、整形式のXML文書を提供することを学びますか?

<t> 
    <node id="1"> 
     <data alias="Show">ShowName1</data> 
     <data alias="Dates">21/04/2009,23/04/2009,27/04/2009,</data> 
    </node> 
    <node id="2"> 
     <data alias="Show">ShowName2</data> 
     <data alias="Dates">22/04/2009,25/04/2009,29/04/2009,</data> 
    </node> 
</t> 

募集結果を生成します:?それ困難こと)である

<show> 
    <name>ShowName1</name> 
    <date>21/04/2009</date> 
</show> 
<show> 
    <name>ShowName2</name> 
    <date>22/04/2009</date> 
</show> 
<show> 
    <name>ShowName1</name> 
    <date>23/04/2009</date> 
</show> 
<show> 
    <name>ShowName2</name> 
    <date>25/04/2009</date> 
</show> 
<show> 
    <name>ShowName1</name> 
    <date>27/04/2009</date> 
</show> 
<show> 
    <name>ShowName2</name> 
    <date>29/04/2009</date> 
</show> 

II。 1つの可能なXSLT 2。0溶液:上記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" 
    exclude-result-prefixes="xs"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

    <xsl:template match="/*"> 

    <xsl:variable name="vAllData" as="xs:string+"> 
      <xsl:for-each select="node"> 
      <xsl:variable name="vName" select="data[@alias='Show']"/> 

       <xsl:for-each select= 
       "tokenize(data[@alias='Dates'], ',')[.]"> 

       <xsl:value-of select="concat($vName, '+',.)"/> 
      </xsl:for-each> 
      </xsl:for-each> 
    </xsl:variable> 

     <xsl:for-each select="$vAllData"> 
      <xsl:sort data-type="number" select= 
      "substring(substring-after(.,'+'),7)"/> 
      <xsl:sort data-type="number" select= 
      "substring(substring-after(.,'+'),4,2)"/> 
      <xsl:sort data-type="number" select= 
      "substring(substring-after(.,'+'),1,2)"/> 

      <show> 
      <name> 
       <xsl:value-of select="substring-before(.,'+')"/> 
      </name> 
      <date> 
       <xsl:value-of select="substring-after(.,'+')"/> 
      </date> 
      </show> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

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

関連する問題