2

与えられた兄弟、そのいくつかは<row>要素であり、いくつかはこのようにそうではありません、

<h />
<row id='v' />
<a />
<b />
<row id='w' />
<d />
<row id='x' />
<row id='y' />
<f />
<r />
<row id='z' />

xslt 1.0を使用して、それらを順番に処理する必要がありますが、行以外のものをグループ化して、次のようにします。

<notRow>
    <h />
</notRow>
<row id='v' />
<notRow>
    <a />
    <b />
</notRow>
<row id='w' />
<notRow>
    <d />
<row id='x' />
<row id='y' />
<notRow>
    <f />
    <r />
</notRow>
<row id='z' />

<row>最初と最後は要素である場合とそうでない場合があります。

どのように?

4

3 に答える 3

1

キーを使用してトリックを実行し、行以外の各要素をその前の行(存在する場合)または親要素(存在しない場合)でグループ化できる場合があります。

<xsl:key name="elementsFollowingRow"
  match="*[not(self::row)]"
  use="generate-id( (.. | preceding-sibling::row )[last()])" />

現在の要素にキーに従って関連付けられた要素がある場合にnotRowに配置する名前付きテンプレートを定義します

<xsl:template name="addNotRow">
  <xsl:if test="key('elementsFollowingRow', generate-id())">
    <notRow>
      <xsl:copy-of select="key('elementsFollowingRow', generate-id())" />
    </notRow>
  </xsl:if>
</xsl:template>

次に、親要素(これらすべての要素rowと非row要素を含む要素)を照合するテンプレートで、実行できます

<xsl:call-template name="addNotRow" />
<xsl:for-each select="row">
  <xsl:copy-of select="." />
  <xsl:call-template name="addNotRow" />
</xsl:for-each>

call-templatefor-eachの外側の最初のnotRowものは、最初のの前に必要なものを処理しrow、for-eachの内側の呼び出しはnotRow、問題の行の後に必要なものを入れます。

于 2013-01-03T01:05:44.683 に答える
1

これと同じくらい短くて単純にすることができます(テンプレートを数回呼び出す必要はありません、、xsl:for-eachxsl:if。完全な変換は次のとおりです。

<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="*/*[not(self::row)]"
          use="concat(generate-id(..), '+',
                      generate-id(preceding-sibling::row[1])
                     )"/>

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

 <xsl:template priority="2" match=
  "*/*[not(self::row)
   and
     (preceding-sibling::*[1][self::row]
    or not(preceding-sibling::*)
     )]">
  <notRow>
    <xsl:copy-of select=
    "key('kFollowing', concat(generate-id(..), '+',
                               generate-id(preceding-sibling::row[1])
                              ))"/>
  </notRow>
 </xsl:template>

 <xsl:template match="*/*[not(self::row)]"/>
</xsl:stylesheet>

この変換が提供されたXMLに適用される場合(整形式にするために単一の最上位要素にラップされます):

<t>
    <h />
    <row id='v' />
    <a />
    <b />
    <row id='w' />
    <d />
    <row id='x' />
    <row id='y' />
    <f />
    <r />
    <row id='z' />
</t>

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

<t>
   <notRow>
      <h/>
   </notRow>
   <row id="v"/>
   <notRow>
      <a/>
      <b/>
   </notRow>
   <row id="w"/>
   <notRow>
      <d/>
   </notRow>
   <row id="x"/>
   <row id="y"/>
   <notRow>
      <f/>
      <r/>
   </notRow>
   <row id="z"/>
</t>

更新

OPは、ノードをコピーするだけでなく、一致するテンプレートによって処理する必要があるという追加の要件を表明しています。

これには最小限の変更のみが必要です

<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="*/*[not(self::row)]"
          use="concat(generate-id(..), '+',
                      generate-id(preceding-sibling::row[1])
                     )"/>

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

 <xsl:template priority="2" match=
  "*/*[not(self::row)
   and
     (preceding-sibling::*[1][self::row]
    or not(preceding-sibling::*)
     )]">
  <notRow>
    <xsl:apply-templates mode="group" select=
    "key('kFollowing', concat(generate-id(..), '+',
                               generate-id(preceding-sibling::row[1])
                              ))"/>
  </notRow>
 </xsl:template>
 <!-- This template can be replaced with whatever processing needed -->
 <xsl:template match="*" mode="group">
  <xsl:copy-of select="."/>
 </xsl:template>
 <xsl:template match="*/*[not(self::row)]"/>
</xsl:stylesheet>

モード「グループ」で動作するテンプレートは、正確に必要な処理を実装するテンプレートに置き換える必要があります。この場合、一致した要素をコピーしますが、実際のアプリケーションでは、必要な処理がここに行われます。

于 2013-01-03T04:24:55.513 に答える
0

これはきれいではありませんが、機能します。

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

    <xsl:template match="t">

        <xsl:if test="row[1]/preceding-sibling::*">
            <notRow>
                <xsl:for-each select="row[1]/preceding-sibling::*" >
                    <xsl:copy />
                </xsl:for-each>
            </notRow>
        </xsl:if>

        <xsl:for-each select="row">
            <xsl:copy-of select="."/>
            <xsl:if test="following-sibling::row[1]/preceding-sibling::*[generate-id(preceding-sibling::row[1])=generate-id(current())]">
                <notRow>
                    <xsl:for-each select="following-sibling::row[1]/preceding-sibling::*[generate-id(preceding-sibling::row[1])=generate-id(current())]">
                        <xsl:copy />
                    </xsl:for-each>
                </notRow>
            </xsl:if>
        </xsl:for-each>

        <xsl:if test="row[last()]/following-sibling::*">
            <notRow>
                <xsl:for-each select="row[last()]/following-sibling::*" >
                    <xsl:copy />
                </xsl:for-each>
            </notRow>
        </xsl:if>

    </xsl:template>


</xsl:stylesheet>

このXMLソースについて

<t>
    <h />
    <i />
    <row id='v' />
    <a />
    <b />
    <row id='w' />
    <d />
    <row id='x' />
    <row id='y' />
    <f />
    <r />
    <row id='z' />
    <i />
</t>

正しい結果を返します。

<notRow>
   <h/>
   <i/>
</notRow>
<row id="v"/>
<notRow>
   <a/>
   <b/>
</notRow>
<row id="w"/>
<notRow>
   <d/>
</notRow>
<row id="x"/>
<row id="y"/>
<notRow>
   <f/>
   <r/>
</notRow>
<row id="z"/>
<notRow>
   <i/>
</notRow>

しかし、もっと簡単なものがあるはずです。

于 2013-01-02T23:44:01.577 に答える