1

私はこの XSLT に慣れていないので、その方法がわかりません。

これは、私が始めたxmlのスニペットです:

<Article>    
<Bullettext>10,00 </Bullettext>  
<Bullettext>8,00 </Bullettext>    
</Article>  
<Article>  
<something>some text</something>  
</Article>  
<Article>  
<Corpsdetexte>Bulgaria</Corpsdetexte>  
<Bullettext>15,0 </Bullettext>  
<Bullettext>10,0 </Bullettext>  
</Article> ` 

これは私が出力したいものです:

<LIST>  
<ITEM>12,00 </ITEM>  
<ITEM>10,00 </ITEM>  
<ITEM>8,00 </ITEM>  
</LIST>  
<P>  
<something>some text</something>  
</P>  

<P>  
<Corpsdetexte>Bulgaria</Corpsdetexte>  
</P>  
<LIST>  
<ITEM>15,0 </ITEM>  
<ITEM>10,0 </ITEM>  
</LIST>  

何か案は??

4

4 に答える 4

5

ルーベンス・ファリアスの回答に対するコメントから(実際には、質問を編集して含める必要があります)、隣接するBulletText要素のグループをリストに変換する一般的な方法が必要なようです。これにより、次の 2 つの質問にたどり着きます。そのようなグループをどのように見つけるか、そしてそれらを見つけた後、それらをどのようにリストに変換するかです。

BulletTextグループを見つけるには、直前の兄弟が要素ではないすべての要素を探す必要がありますBulletText。それらのそれぞれがグループを開始し、それらはリストに変換しようとしている要素です。したがって、最初にやりたいことは、それらを見つける XPath 式を作成することです。

BulletText[not(preceding-sibling::*[1][name()='BulletText'])]

その XPath 式の述語を見ると、必要なことはまさに私が言ったことです。つまり、最初に先行する兄弟 ( ) の名前が ではBulletTextない場合、要素に一致します。要素に先行する兄弟がない場合でも、この式はそれに一致することに注意してください。preceding-sibling::*[1]BulletText

これで、これらのグループの開始要素に一致するテンプレートを作成できます。このテンプレートには何を入れますか? これらの要素を要素に変換するLISTので、テンプレートは次のようになります。

<LIST>
   ...
</LIST>

簡単です。しかし、そのリストに入力する要素をどのように見つけるのでしょうか? 対処しなければならないケースが 2 つあります。

1 つ目は単純です。次のすべての兄弟がBulletText要素である場合、この要素とそれに続くすべての兄弟をリストに入力します。

2番目は難しいです。要素ではない次の兄弟がある場合BulletText、リストを現在の要素の親のすべての子にする必要があります。現在の要素から始まり、停止要素の前で終わります。count()これは、開始インデックスと終了インデックスを計算する関数と、position()各要素の位置を見つける関数を使用する必要がある場合です。

完成したテンプレートは次のようになります。

<xsl:template match="BulletText[not(preceding-sibling::*[1][name()='BulletText'])]">
  <!-- find the element that we want to stop at -->
  <xsl:variable name="stop" select="./following-sibling::*[name() != 'BulletText'][1]"/>
  <LIST>
    <xsl:choose>
      <!-- first, the simple case:  there's no element we have to stop at -->
      <xsl:when test="not($stop)">
        <xsl:apply-templates select="." mode="item"/>
        <xsl:apply-templates select="./following-sibling::BulletText" mode="item"/>
      </xsl:when>
      <!-- transform all elements between the start and stop index into items -->
      <xsl:otherwise>
        <xsl:variable name="start_index" select="count(preceding-sibling::*) + 1"/>
        <xsl:variable name="stop_index" select="count($stop/preceding-sibling::*)"/>
        <xsl:apply-templates select="../*[position() &gt;= $start_index 
                                      and position() &lt;= $stop_index]"
                             mode="item"/>
      </xsl:otherwise>
    </xsl:choose>
  </LIST>
</xsl:template>

他に 2 つのテンプレートが必要です。BulletText1 つは要素を項目に変換します。ここでは、現在使用しているテンプレートを呼び出さずmodeに要素に適用できるように使用します。BulletText

<xsl:template match="BulletText" mode="item">
   <ITEM>
      <xsl:value-of select="."/>
   </ITEM>
</xsl:template>

次に、最初のテンプレートが出力を生成することから一致しないBulletText要素を保持するテンプレートも必要です (恒等変換を使用している場合、それらは単にコピーされるためです)。

<xsl:template match='BulletText'/>

XSLT のテンプレート優先ルールの魔法により、BulletText両方のテンプレートが一致する要素は最初のテンプレートによって変換され、残りはこのテンプレートによってキャッチされます。

これら 3 つのテンプレートを恒等変換に追加するだけで、準備完了です。

于 2010-01-14T20:45:56.230 に答える
1

3 つのテンプレートを使用して兄弟をグループ化する

現在、この質問に対する有効な回答がいくつかありますが、実際には、3 つのテンプレートと ID を使用して、兄弟を非常に簡単にグループ化できます。

まず、すべてのノードを削除してその優先順位を設定するテンプレートが必要です。これにより、別のテンプレートでオーバーライドできるようになります。

<xsl:template match="Bullettext" priority="1"/>

次に、それ自体が先行していないノードに一致するテンプレートを定義し、より高い優先度を割り当てます。このテンプレートはグループを挿入し、別のモードでノードのコピーを開始します。

<xsl:template match="Bullettext[not(preceding-sibling::*[1][self::Bullettext])]" priority="2">
  <LIST>
    <xsl:apply-templates select="." mode="bullet-list"/>
  </LIST>
</xsl:template>

最後に、グループ化される項目を処理する末尾再帰テンプレートを定義します。

<xsl:template match="Bullettext" mode="bullet-list">
  <ITEM>
    <xsl:apply-templates select="@*|node()"/>
  </ITEM>
  <xsl:apply-templates select="following-sibling::*[1][self::Bullettext]" mode="bullet-list"/>
</xsl:template>

例の Bullettext 要素をグループ化する完全なスタイルシートを次に示します。

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

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

  <!-- Removes the Bullettext elements in the default mode. -->
  <xsl:template match="Bullettext" priority="1" />

  <!-- Creates the LIST elements around the removed Bullettext elements. -->
  <xsl:template match="Bullettext[not(preceding-sibling::*[1][self::Bullettext])]" priority="2">
    <LIST>
      <xsl:apply-templates select="." mode="bullet-list" />
    </LIST>
  </xsl:template>

  <!-- Converts sequential Bullettext elements into ITEM elements. -->
  <xsl:template match="Bullettext" mode="bullet-list">
    <ITEM>
      <xsl:apply-templates select="@*|node()" />
    </ITEM>
    <xsl:apply-templates select="following-sibling::*[1][self::Bullettext]" mode="bullet-list" />
  </xsl:template>

</xsl:stylesheet>
于 2012-12-06T09:12:08.527 に答える
1

条件付きの deep-copyを探していると思います。

あなたの状況に合わせて書き直された上記のリンクのコードは次のとおりです。

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

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

    <!-- nodes with Bullettext children -->
    <xsl:template match="*[Bullettext]">
        <!-- for every child -->
        <xsl:copy>
            <xsl:for-each select="*">
                <!-- if child is a Bullettext and it has a Bullettext before it, don't copy it (it has already been copied) -->
                <xsl:if test="not(local-name(.) = 'Bullettext' and local-name(./preceding-sibling::*[1]) = 'Bullettext')">
                    <xsl:choose>
                        <xsl:when test="local-name(.) = 'Bullettext'">
                            <!-- copy all Bullettext children adjacent to this one and each other -->
                            <LIST>
                                <xsl:call-template name="get-all-adjacent-siblings">
                                    <xsl:with-param name="sibling-before" select="." />
                                </xsl:call-template>
                            </LIST>
                        </xsl:when>
                        <xsl:otherwise>
                            <!-- copy non-Bullettext child -->
                            <xsl:apply-templates select="." />
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:if>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

    <xsl:template name="get-all-adjacent-siblings">
        <xsl:param name="sibling-before" />
        <!-- return me -->
        <xsl:copy>
            <xsl:value-of select="$sibling-before" />
        </xsl:copy>
        <!-- return my adjacent Bullettext siblings below me -->
        <xsl:if test="local-name($sibling-before/following-sibling::*[1]) = 'Bullettext'">
            <xsl:call-template name="get-all-adjacent-siblings">
                <xsl:with-param name="sibling-before" select="$sibling-before/following-sibling::*[1]" />
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

私が使用した入力は次のとおりです。

<?xml version="1.0" encoding="utf-8"?>
<Articles>
    <Article>
        <Bullettext>10,00 </Bullettext>
        <Bullettext>8,00 </Bullettext>
    </Article>
    <Article>
        <something>some text</something>
    </Article>
    <Article>
        <Corpsdetexte>Bulgaria</Corpsdetexte>
        <deeper>
            <before>dogs</before>
            <Bullettext>15,0 </Bullettext>
            <Bullettext>10,0 </Bullettext>
            <middle>cats</middle>
            <Bullettext>25,0 </Bullettext>
            <Bullettext>20,0 </Bullettext>
            <after>cows</after>
        </deeper>
    </Article>
</Articles>

そして、それは私に与えました:

<?xml version="1.0" encoding="UTF-8"?>
<Articles>
    <Article>
        <LIST>
            <Bullettext>10,00 </Bullettext>
            <Bullettext>8,00 </Bullettext>
        </LIST>
    </Article>
    <Article>
        <something>some text</something>
    </Article>
    <Article>
        <Corpsdetexte>Bulgaria</Corpsdetexte>
        <deeper>
            <before>dogs</before>
            <LIST>
                <Bullettext>15,0 </Bullettext>
                <Bullettext>10,0 </Bullettext>
            </LIST>
            <middle>cats</middle>
            <LIST>
                <Bullettext>25,0 </Bullettext>
                <Bullettext>20,0 </Bullettext>
            </LIST>
            <after>cows</after>
        </deeper>
    </Article>
</Articles>

同じスタイルシートに s を追加するなどの他の変換を行う場合は少し面倒です<p></p>が、2 つのスタイルシートで 2 段階の変換を行う場合、最初に上記の条件付きディープ コピーを実行し、次に 2 番目に結果を使用して主な変換を実行します。最初の、あなたは行く準備ができているはずです。

于 2010-01-14T13:38:08.573 に答える
0

次のようなことを試してください:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/Articles">
    <LIST>
      <xsl:for-each select="Article[1]/Bullettext">
        <ITEM>
          <xsl:value-of select="." />
        </ITEM>
      </xsl:for-each>
    </LIST>

    <p>
      <something>
        <xsl:value-of select="Article[2]/something" />
      </something>
    </p>

    <p>
      <Corpsdetexte>
        <xsl:value-of select="Article[3]/Corpsdetexte" />
      </Corpsdetexte>
    </p>

    <LIST>
      <xsl:for-each select="Article[4]/Bullettext">
        <ITEM>
          <xsl:value-of select="." />
        </ITEM>
      </xsl:for-each>
    </LIST>
  </xsl:template>
</xsl:stylesheet>
于 2010-01-14T11:21:58.453 に答える