2011-06-23 6 views
3

HTMLに変換したいXMLがあるとします。 XMLは順序付きセクションに分割されています。XSLT 1.0を使用して、いくつかの基準に基づいてXML要素をバケットにグループ化します。

<?xml version="1.0" encoding="utf-8"?> 
<root> 
    <section attr="someCriteria"> 
    <h1>Title 1</h1> 
    <p>paragraph 1-1</p> 
    <p>paragraph 1-2</p> 
    </section> 
    <section attr="someOtherCriteria"> 
    <h3>Subtitle 2</h3> 
    <ul> 
     <li>list item 2-1</li> 
     <li>list item 2-2</li> 
     <li>list item 2-3</li> 
     <li>list item 2-4</li> 
    </ul> 
    </section> 
    <section attr="anotherSetOfCriteria"> 
    <warning> 
     Warning: This product could kill you 
    </warning> 
    </section> 
    <section attr="evenMoreCriteria"> 
    <disclaimer> 
     You were warned 
    </disclaimer> 
    </section> 
    <section attr="criteriaSupreme"> 
    <p>Copyright 1999-2011</p> 
    </section> 
</root> 

これらのXML文書はいくつかあります。 基準に基づいてこれらのセクションをグループ化して変換する必要があります。 2種類のバケツがあります。 第二節では、基準を満たしている場合

  • だから、最初のセクションでは、それは もこのバケットに行こう「FormatOne」バケツの資格 に バケツに(例えば<div class="FormatOne"></div>
  • を行く
  • 3番目のセクションは異なる バケット(例えば <div class="FormatTwo"></div>)、新しい バケットが作成され、セクションを必要とする場合
  • は 内容は、このバケットに配置されている
  • 4番目のセクションのためのバケットが、新しい バケットが再び作成された「FormatOne」(以前の形式よりも異なっている)とセクション 内容を必要とする場合は、各セクションがに行くと、このバケット
  • などに配置されています前のセクションと同じバケット。同じフォーマットの場合そうでない場合は、新しいバケットが作成されます。

だから、文書ごとに、バケットを分離するためのロジックに応じて、文書には、このように終わる可能性があります

<body> 
    <div class="FormatOne"> 
    <h1>Title 1</h1> 
    <p>paragraph 1-1</p> 
    <p>paragraph 1-2</p> 
    <h3>Subtitle 2</h3> 
    <ul> 
     <li>list item 2-1</li> 
     <li>list item 2-2</li> 
     <li>list item 2-3</li> 
     <li>list item 2-4</li> 
    </ul> 
    </div> 
    <div class="FormatTwo"> 
    <span class="warningText"> 
     Warning: This product could kill you 
    </span> 
    </div> 
    <div class="FormatOne"> 
    <span class="disclaimerText"> You were warned</span> 
    <p class="copyright">Copyright 1999-2011</p> 
    </div> 
</body> 

この:

<body> 
    <div class="FormatOne"> 
    <h1>Title 1</h1> 
    <p>paragraph 1-1</p> 
    <p>paragraph 1-2</p> 
    <h3>Subtitle 2</h3> 
    </div> 
    <div class="FormatTwo"> 
    <ul> 
     <li>list item 2-1</li> 
     <li>list item 2-2</li> 
     <li>list item 2-3</li> 
     <li>list item 2-4</li> 
    </ul> 
    </div> 
    <div class="FormatOne"> 
    <span class="warningText"> 
     Warning: This product could kill you 
    </span> 
    <span class="disclaimerText"> You were warned</span> 
    <p class="copyright">Copyright 1999-2011</p> 
    </div> 
</body> 

かさえ、この:

<body> 
    <div class="FormatOne"> 
    <h1>Title 1</h1> 
    <p>paragraph 1-1</p> 
    <p>paragraph 1-2</p> 
    <h3>Subtitle 2</h3> 
    <ul> 
     <li>list item 2-1</li> 
     <li>list item 2-2</li> 
     <li>list item 2-3</li> 
     <li>list item 2-4</li> 
    </ul> 
    <span class="warningText"> 
     Warning: This product could kill you 
    </span> 
    <span class="disclaimerText"> You were warned</span> 
    <p class="copyright">Copyright 1999-2011</p> 
    </div> 
</body> 

セクションの定義方法によって異なります。

このタイプのグループ化マジックを実行するためにXSLTを使用する方法はありますか?

助けがあれば助かります。 ありがとう!

答えて

3

私は、各セクションに順番に当たるという解決策を考え出しました。各セクションの処理は、「シェル」と「コンテンツ」の2つの部分に分かれています。"シェル"は<div class="FormatOne">...</div>ビットのレンダリングを担当し、一致しないセクションが見つかるまでが現れるまで、現在のセクションとすべての次のセクションの実際の内容をレンダリングします。

一致しないセクションが見つかると、コントロールはそのセクションの「シェル」テンプレートに戻ります。

これは興味深いビットの柔軟性を提供します。「シェル」テンプレートは、一致するものが非常に攻撃的であり、「内容」セクションはより分かりやすいものです。具体的には、最初の出力例では<span class="warningText">...</span>と表示されるようにwarning要素が必要です。これは、より密接に一致するテンプレートで実現されます。

すべての「コンテンツ」テンプレートは、現在のセクションのコンテンツをレンダリングした後、「次の」適切なコンテンツセクションを探す名前付きテンプレートを呼び出します。これは、「合致する」セクションとしての資格を決定するためのルールを統合するのに役立ちます。

You can see a working example here。ここで

はあなたの最初の例でを求めたものを複製するために構築された、私のコードです:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" /> 

    <xsl:template match="/"> 
     <body> 
      <xsl:apply-templates select="/root/section[1]" mode="shell" /> 
     </body> 
    </xsl:template> 

    <xsl:template match="section[ 
     @attr = 'someCriteria' or 
     @attr = 'someOtherCriteria' or 
     @attr = 'evenMoreCriteria' or 
     @attr = 'criteriaSupreme']" mode="shell"> 

     <div class="FormatOne"> 
      <xsl:apply-templates select="." mode="contents" /> 
     </div> 

     <xsl:apply-templates select="following-sibling::section[ 
      @attr != 'someCritera' and 
      @attr != 'someOtherCriteria' and 
      @attr != 'evenMoreCriteria' and 
      @attr != 'criteriaSupreme'][1]" mode="shell" /> 

    </xsl:template> 

    <xsl:template name="nextFormatOne"> 
     <xsl:variable name="next" select="following-sibling::section[1]" /> 
     <xsl:if test="$next[ 
      @attr = 'someCriteria' or 
      @attr = 'someOtherCriteria' or 
      @attr = 'evenMoreCriteria' or 
      @attr = 'criteriaSupreme']"> 
      <xsl:apply-templates select="$next" mode="contents" /> 
     </xsl:if> 
    </xsl:template> 

    <xsl:template match="section[ 
     @attr = 'someCriteria' or 
     @attr = 'someOtherCriteria']" mode="contents"> 

     <xsl:copy-of select="*" /> 

     <xsl:call-template name="nextFormatOne" /> 
    </xsl:template> 

    <xsl:template match="section[@attr = 'evenMoreCriteria']" mode="contents"> 
     <span class="disclaimerText"> 
      <xsl:value-of select="disclaimer" /> 
     </span> 

     <xsl:call-template name="nextFormatOne" /> 
    </xsl:template> 

    <xsl:template match="section[@attr = 'criteriaSupreme']" mode="contents"> 
     <p class="copyright"> 
      <xsl:value-of select="p" /> 
     </p> 

     <xsl:call-template name="nextFormatOne" /> 
    </xsl:template> 

    <xsl:template match="section[@attr = 'anotherSetOfCriteria']" mode="shell"> 
     <div class="FormatTwo"> 
      <xsl:apply-templates select="." mode="contents" /> 
     </div> 
     <xsl:apply-templates select=" 
      following-sibling::section[@attr != 'anotherSetOfCriteria'][1]" 
      mode="shell" /> 
    </xsl:template> 

    <xsl:template name="nextFormatTwo"> 
     <xsl:variable name="next" select="following-sibling::section[1]" /> 
     <xsl:if test="$next[@attr = 'anotherSetOfCriteria']"> 
      <xsl:apply-templates select="$next" mode="contents" /> 
     </xsl:if> 
    </xsl:template> 

    <xsl:template 
     match="section[@attr = 'anotherSetOfCriteria']" 
     mode="contents"> 

     <span class="warningText"> 
      <xsl:value-of select="warning" /> 
     </span> 

     <xsl:call-template name="nextFormatTwo" /> 
    </xsl:template> 

</xsl:stylesheet> 
+0

これは素晴らしいです!ありがとう! – RPNinja

1

「彼らは同じフォーマットであれば、各セクションでは、前のセクションと同じバケツに入るかどうません。新しいバケットが作成されます。あなたが説明してきた何

は、本質的にXSLT 2.0で

<xsl:for-each-group group-adjacent="...."> 

命令によって実行されるタスクです。これは、 "条件"をバケット名に変換し、この関数をgroup-adjacent属性内で呼び出す関数を書くことができることを前提としています。

したがって、XSLT 1.0を使用する必要があるという制約がどれくらいありますか?

1.0で立ち往生している場合は、Chris Nielsenの提案したような兄弟再帰のデザインパターンを使用する必要があります。

+0

ありがとう、@マイケル!私たちはMicrosoftのショップにいますが、残念ながら、MSはXSLT 2.0をサポートしていません。さらに、私たちは[Saxon](http://saxon.sourceforge.net/)のようなものを実装することができませんでした。 – RPNinja

関連する問題