2016-09-15 3 views
2

私はCSVに変換したいXML出力をいくつか持っていますが、キーと値のペアを含むデータでは最も難しいと判明しています。私は何日も何度も反復を試みましたが、ついには助けが必要です。これは、XSLT 1.0で変換する必要があるXMLです。キーと値のペアを持つCSVへのXSLT

<?xml version="1.0" encoding="UTF-8"?> 
<status> 
    <snapshot> 
     <metrics> 
      <entry> 
       <key>time</key> 
       <value>1001</value> 
      </entry> 
      <entry> 
       <key>bytes</key> 
       <value>104</value> 
      </entry> 
      <entry> 
       <key>input</key> 
       <value>13321</value> 
      </entry> 
      <entry> 
       <key>output</key> 
       <value>11002</value> 
      </entry> 
     </metrics> 
     <timestamp>2016-01-12T01:00</timestamp> 
     <metrics> 
      <entry> 
       <key>time</key> 
       <value>1002</value> 
      </entry> 
      <entry> 
       <key>bytes</key> 
       <value>105</value> 
      </entry> 
      <entry> 
       <key>input</key> 
       <value>13322</value> 
      </entry> 
      <entry> 
       <key>output</key> 
       <value>11003</value> 
      </entry> 
     </metrics> 
     <timestamp>2016-01-12T02:00</timestamp> 
    </snapshot> 
</status> 

私は、出力は次のようになりたいと思います:

time,bytes,input,output,timestamp 
1001,104,13321,11002,2016-01-12T01:00 
1002,105,13322,11003,2016-01-12T02:00 

===私が使用していますXSLTを追加する===

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:variable name="delimiter" select="','"/> 

    <xsl:key name="field" match="entry/*" use="name()"/> 

    <xsl:template match="/"> 

     <xsl:for-each select="/*/*/*/*/*[generate-id()=generate-id(key('field', name())[1])]"> 
      <xsl:value-of select="name()"/> 

      <xsl:if test="position() != last()"> 
       <xsl:value-of select="$delimiter"/> 
      </xsl:if> 
     </xsl:for-each> 

     <xsl:text>&#xa;</xsl:text> 

     <xsl:for-each select="/*/sObject"> 

      <xsl:variable name="property" select="." /> 
      <xsl:for-each select="$property/*"> 

       <xsl:variable name="value" select="." /> 
       <xsl:value-of select="$value"/> 
       <xsl:if test="position() != last()"> 
        <xsl:value-of select="$delimiter"/> 
       </xsl:if> 
       <xsl:if test="position() = last()"> 
        <xsl:text>&#xa;</xsl:text> 
       </xsl:if> 

      </xsl:for-each> 

     </xsl:for-each> 


    </xsl:template> 
</xsl:stylesheet> 
+0

サイドノート...私は@dnovatchevからXSLTコードの一部を適応しようとしたが、私は、キーと値のペアのシナリオにそれを適応の問題を抱えています。 –

+1

すべての 'metrics'が同じエントリーを同じ順序で持つと仮定できますか? 、異なる値でのみ? –

+0

@shellter私が作業しているコードを追加する。 –

答えて

1

自分の与えられた例のXMLによると、情報をお試しください。XSLT 1.0これは、ダイナミックなアプローチで改善された簡易版です。あなたのXMLがわずかに変化した場合、あなたはあなたのスタイルシートを変更することを余儀なくされていない(例えばentriesを追加する。):

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0"> 

    <xsl:output method="text"/> 
    <xsl:strip-space elements="status snapshot"/> 

    <xsl:template match="snapshot"> 

     <!-- generate the headline --> 
     <xsl:apply-templates select="metrics[1]/entry/key | timestamp[1]" mode="heading"/> 
     <xsl:text>&#10;</xsl:text> 

     <!-- generate the content --> 
     <xsl:for-each select="metrics"> 
      <xsl:for-each select="entry/value"> 
       <xsl:value-of select="concat(., ',')"/> 
      </xsl:for-each> 
      <xsl:value-of select="following-sibling::*[name() = 'timestamp'][1]"/> 
      <xsl:text>&#10;</xsl:text> 
     </xsl:for-each> 

    </xsl:template> 

    <xsl:template match="metrics/entry/key" mode="heading"> 
     <xsl:value-of select="concat(., ',')"/> 
    </xsl:template> 

    <xsl:template match="timestamp" mode="heading"> 
     <xsl:value-of select="name()"/> 
    </xsl:template> 

</xsl:stylesheet> 

結果:

time,bytes,input,output,timestamp 
1001,104,13321,11002,2016-01-12T01:00 
1002,105,13322,11003,2016-01-12T02:00 

要件:

すべてentryとをその子は常に存在し、同じです。

+0

は完全に機能します。どうもありがとうございました。 1つのしわを加えることができますか?これらの2つのレコードのそれぞれにタイムスタンプを追加する場合、どのようにxsltを変更できますか?私は別のxsl:for-each select = "timestamp"ブロックを追加することで、いくつかのスタブを取ってきましたが、失敗しました。 –

+0

私の改善されたバージョンを参照してください。注意してください、あなたの "受け入れられた"答えは完全に静的です。それはほとんどの場合悪いことです。ただ働くだけでは必ずしもベストではありません。 – uL1

0

これはXSLT 1.0のものです

必須の4つの列を定義します。次に、一致するキー/値ペアのみを選択します。この方法では、存在しないキーと値のペアが出力で考慮され、追加のペアは無視されます。区切り文字と列名はパラメータとして渡すことができます。

短所:キー名を変更した場合の柔軟性がない。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="text"/> 
<xsl:param name="del" select="','"/> 
<xsl:param name="col1" select="'time'"/> 
<xsl:param name="col2" select="'bytes'"/> 
<xsl:param name="col3" select="'input'"/> 
<xsl:param name="col4" select="'output'"/> 
<xsl:param name="col5" select="'timestamp'"/> 
<xsl:template match="/status/snapshot"> 
    <xsl:value-of select="concat($col1, $del, $col2, $del, $col3, $del, $col4, $del, $col5, '&#10;')"/> 
    <xsl:for-each select="metrics"> 
     <xsl:variable name="pos" select="position()"/> 
     <xsl:value-of select="concat(entry[key = $col1]/value, $del)"/> 
     <xsl:value-of select="concat(entry[key = $col2]/value, $del)"/> 
     <xsl:value-of select="concat(entry[key = $col3]/value, $del)"/> 
     <xsl:value-of select="concat(entry[key = $col4]/value, $del)"/> 
     <xsl:value-of select="concat(../timestamp[$pos], '&#10;')"/> 
    </xsl:for-each> 
</xsl:template> 

+0

他にもあります。ありがとう!タイムスタンプフィールドを追加する質問を編集しました。他の列として追加する方法についてのアイデアはありますか? *タイムスタンプ*は、キーと値のペアのすぐ外側にあります。 –

関連する問題