8

シーケンシャルな XML ノード リストを階層構造に変換する必要がありますが、XSLT 固有の知識のギャップに遭遇しました。入力 XML には、記事、色、およびサイズが含まれています。以下のサンプルでは、​​「Record1」は記事、「Record2」は色、「Record3」はサイズを表しています。色とサイズ (record2 と record3) の要素の数はさまざまです。

<root>
 <Record1>...</Record1>
 <Record2>...</Record2>
 <Record3>...</Record3>
 <Record3>...</Record3>
 <Record2>...</Record2>
 <Record3>...</Record3>
 <Record3>...</Record3>
 <Record3>...</Record3>
 <Record3>...</Record3>
 <Record1>...</Record1>
 <Record2>...</Record2>
 <Record3>...</Record3>
 <Record3>...</Record3>
 <Record2>...</Record2>
 <Record3>...</Record3>
 <Record3>...</Record3>
 <Record3>...</Record3>
 <Record3>...</Record3>
</root> 

すべてのフィールドは同じ階層レベルにありますが、出力としてこの構造を作成する必要があります。

<root>
 <article>              -> Record1
  <color>               -> Record2
   <size>...</size>     -> Record3
   <size>...</size>     -> Record3
  </color>
  <color>               -> Record2
   <size>...</size>     -> Record3
   <size>...</size>     -> Record3
   <size>...</size>     -> Record3
   <size>...</size>     -> Record3
  </color>
 </article>
 <article>              -> Record1
  <color>               -> Record2
   <size>...</size>     -> Record3
   <size>...</size>     -> Record3
  </color>
  <color>               -> Record2
   <size>...</size>     -> Record3
   <size>...</size>     -> Record3
   <size>...</size>     -> Record3
   <size>...</size>     -> Record3
  </color>
 </article>
</root>

ノードを順番に反復しようとしましたが、たとえば、'color' (=record2) ノードが処理されている間、'article' (=record1) ノード タグを閉じないままにする必要があります。'color' が閉じられていない 'size' (=record3) の処理についても同じことが言えますが、それは XSLT では許可されていません。私の次のアイデアは、すべての記事、色、およびサイズ レベルのテンプレートを呼び出すことでしたが、たとえば、現在の「record2」と「record1」で表される次の記事の間のすべての「record3」ノードを選択する方法がわかりません。

XSLT 1.0 のみをサポートする BizTalk Server でこの変換が必要なため、XSLT バージョンにも制限があります。

誰かが私を正しい方向に押し進めることができますか?

4

3 に答える 3

3

DevNullとNovatchevのソリューションはどちらも実行可能です。3番目の解決策、そして私にとって最もエレガントに思える解決策は、「兄弟再帰」を使用することです。コードを完全に提供することはしませんが、次のようなルートのテンプレートルールから始めます。

<xsl:template match="root">
  <xsl:apply-templates select="*[1]"/>
</xsl:template>

次に、次のようなさまざまな「レベル」のテンプレートルールを用意します。

<xsl:template match="record1">
  <section1>
    <xsl:apply-templates select="following-sibling::*[1][self::record2]"/>
  </section1>
  <xsl:apply-templates select="following-sibling::record1[1]"/>
</xsl:template>

同様に各レベルで。このソリューションは、おそらく他のソリューションよりも高速で簡潔ですが、慣れるまでは少し「気が遠くなる」可能性があります。それを理解するための鍵は、各レベルで最初に最初の「論理子」を処理することです。つまり、現在の要素よりも深いレベルにある場合は、フラットシーケンスの次の要素を処理します。次に、次の「論理兄弟」(現在の要素と同じレベルにあるフラットシーケンスの次の要素)を処理します。もちろん、このソリューションは、レベルが欠落している可能性がある場合や、レベル番号が要素名ではなく属性で示されている場合に適合させることができます。レベルの数が事前にわからない場合にも適応できます。「」を選択する単一のルールを使用するだけです。

于 2012-12-07T09:28:31.033 に答える
3

XSLT 1.0 オプションの 1 つを次に示します。Record1 と Record2 の値で何をしたいのかよくわからないので、それらをval属性に入れました。

XML 入力

<root>
    <Record1>article1</Record1>
    <Record2>color1</Record2>
    <Record3>size1</Record3>
    <Record3>size2</Record3>
    <Record2>color2</Record2>
    <Record3>size3</Record3>
    <Record3>size4</Record3>
    <Record3>size5</Record3>
    <Record3>size6</Record3>
    <Record1>article2</Record1>
    <Record2>color3</Record2>
    <Record3>size7</Record3>
    <Record3>size8</Record3>
    <Record2>color4</Record2>
    <Record3>size9</Record3>
    <Record3>size10</Record3>
    <Record3>size11</Record3>
    <Record3>size12</Record3>
</root>

XSLT1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/*">
        <xsl:copy>
            <xsl:apply-templates select="Record1"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Record1">
        <article val="{.}">
            <xsl:apply-templates select="following-sibling::Record2[generate-id(preceding-sibling::Record1[1])=generate-id(current())]"/>
        </article>
    </xsl:template>

    <xsl:template match="Record2">
        <color val="{.}">
            <xsl:apply-templates select="following-sibling::Record3[generate-id(preceding-sibling::Record2[1])=generate-id(current())]"/>
        </color>
    </xsl:template>

    <xsl:template match="Record3">
        <size>
            <xsl:value-of select="."/>
        </size>
    </xsl:template>

</xsl:stylesheet>

XML 出力

<root>
   <article val="article1">
      <color val="color1">
         <size>size1</size>
         <size>size2</size>
      </color>
      <color val="color2">
         <size>size3</size>
         <size>size4</size>
         <size>size5</size>
         <size>size6</size>
      </color>
   </article>
   <article val="article2">
      <color val="color3">
         <size>size7</size>
         <size>size8</size>
      </color>
      <color val="color4">
         <size>size9</size>
         <size>size10</size>
         <size>size11</size>
         <size>size12</size>
      </color>
   </article>
</root>
于 2012-12-06T17:30:39.607 に答える