-1

XSLT を使用して次のことを行うクリーンな方法を探しています。

このソースを変換します:

<para>blah blah</para>
<list>num1</list>
<list>num2</list>
<list>num3</list>
<para>blah blah</para>
<list>num1</list>
<list>num2</list>
<para>blah blah blah blah blah</para>

この出力に:

<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
    <li>num3</li>
</ol>
<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
</ol>
<p>blah blah blah blah blah</p>

がいくつあるか正確にはわからないことに注意し<list>てください。

これまでのところ、私はこれを持っています:

<xsl:template match="para">
    <p><xsl:value-of select="." /></p>
</xsl:template>

<xsl:template match="list">
    <ol><li><xsl:value-of select="." /></li></ol>
</xsl:template>

しかし、私の出力は次のようになります。

<p>blah blah</p>    
<ol><li>num1</li></ol>
<ol><li>num2</li></ol>
<ol><li>num3</li></ol>
<p>blah blah</p>
<ol><li>num1</li></ol>
<ol><li>num2</li></ol>
<p>blah blah blah blah blah</p>

要素が重複している理由は<ol>わかっていますが、それを止める方法がわかりません。かなりの頭の体操。

どんな助けでも大歓迎です。

4

3 に答える 3

2

このXSLT1.0スタイルシート:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()">
        <xsl:apply-templates select="node()[1]|following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="para">
        <p>
            <xsl:value-of select="."/>
        </p>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="list[preceding-sibling::node()[1][not(self::list)]]">
        <ol>
            <xsl:call-template name="makeList"/>
        </ol>
        <xsl:apply-templates select="following-sibling::node()
                                              [not(self::list)][1]"/>
    </xsl:template>
    <xsl:template match="list" name="makeList">
        <li>
            <xsl:value-of select="."/>
        </li>
        <xsl:apply-templates select="following-sibling::node()[1]
                                              [self::list]"/>
    </xsl:template>
</xsl:stylesheet>

出力:

<p>blah blah</p>
<ol>
        <li>num1</li>
        <li>num2</li>
        <li>num3</li>
</ol>
<p>blah blah</p>
<ol>
        <li>num1</li>
        <li>num2</li>
</ol>
<p>blah blah blah blah blah</p>

注:きめの細かいトラバーサル。

編集:コンパクトコード。

于 2010-10-12T22:53:22.470 に答える
2

XSLT 2.0 には、特にこの種の操作用のツールがあります。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="xml">
        <xsl:for-each-group select="*" group-adjacent="boolean(self::list)">
            <xsl:choose>
                <xsl:when test="current-grouping-key()">
                    <ol>
                        <xsl:apply-templates select="current-group()"/>
                    </ol>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="current-group()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:template>
    <xsl:template match="para">
        <p>
            <xsl:apply-templates/>
        </p>
    </xsl:template>
    <xsl:template match="list">
        <li>
            <xsl:apply-templates/>
        </li>
    </xsl:template>
</xsl:stylesheet>

この XML では:

<xml>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <list>num3</list>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <para>blah blah blah blah blah</para>
</xml>

目的の出力が得られます。

<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
    <li>num3</li>
</ol>
<p>blah blah</p>
<ol>
    <li>num1</li>
    <li>num2</li>
</ol>
<p>blah blah blah blah blah</p>

http://www.w3.org/TR/xslt20/#xsl-for-each-groupで for-each-group を読む必要があります。

于 2010-10-13T08:21:55.463 に答える
0

この変換

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kFollowing" match="list"
  use="generate-id(preceding-sibling::para[1])"/>

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

 <xsl:template match="para">
  <p>
    <xsl:apply-templates/>
  </p>
   <xsl:variable name="vFol"
    select="key('kFollowing',generate-id())"/>
   <xsl:if test="$vFol">
      <ol>
       <xsl:apply-templates mode="copy"
           select="key('kFollowing',generate-id())"/>
      </ol>
  </xsl:if>
 </xsl:template>

 <xsl:template match="list" mode="copy">
  <li><xsl:value-of select="."/></li>
 </xsl:template>
 <xsl:template match="list"/>
</xsl:stylesheet>

次のXMLドキュメントに適用した場合(提供された入力を単一の最上位要素にラップします):

<t>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <list>num3</list>
    <para>blah blah</para>
    <list>num1</list>
    <list>num2</list>
    <para>blah blah blah blah blah</para>
</t>

必要な正しい結果を生成します

<t>
    <p>blah blah</p>
    <ol>
        <li>num1</li>
        <li>num2</li>
        <li>num3</li>
    </ol>
    <p>blah blah</p>
    <ol>
        <li>num1</li>
        <li>num2</li>
    </ol>
    <p>blah blah blah blah blah</p>
</t>

更新:OPはコメントで、要素以外の要素が隣接する兄弟のグループを区切ることができるソリューションが必要であることを示しています。listlist

変更された質問の解決策は次のとおりです。

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

 <xsl:key name="kFollowing" match="list"
  use="generate-id(preceding-sibling::*[not(self::list)][1])"/>

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

 <xsl:template match="*[not(self::list) and following-sibling::*[1][self::list]]">
  <xsl:call-template name="identity"/>
   <xsl:variable name="vFol"
    select="key('kFollowing',generate-id())"/>
   <xsl:if test="$vFol">
      <ol>
       <xsl:apply-templates mode="copy"
           select="key('kFollowing',generate-id())"/>
      </ol>
  </xsl:if>
 </xsl:template>

 <xsl:template match="list" mode="copy">
  <li><xsl:value-of select="."/></li>
 </xsl:template>
 <xsl:template match="list"/>
</xsl:stylesheet>

この変換が次のXMLドキュメントに適用される場合(区切り要素の名前がランダムになっていることに注意してください)。

<t>
    <bara>blah blah</bara>
    <list>num1</list>
    <list>num2</list>
    <list>num3</list>
    <vara>blah blah</vara>
    <list>num1</list>
    <list>num2</list>
    <dara>blah blah blah blah blah</dara>
</t>

必要な正しい結果が生成されます:

<t>
    <bara>blah blah</bara>
    <ol>
        <li>num1</li>
        <li>num2</li>
        <li>num3</li>
    </ol>
    <vara>blah blah</vara>
    <ol>
        <li>num1</li>
        <li>num2</li>
    </ol>
    <dara>blah blah blah blah blah</dara>
</t>
于 2010-10-12T22:48:21.770 に答える