xsl группировать узлы между другими узлами? - PullRequest
3 голосов
/ 27 октября 2010

Я не могу понять, как создать xsl для группировки некоторых узлов между другими узлами. По сути, каждый раз, когда я вижу 'SPLIT', мне нужно завершить div и создать новый.

XML выглядит так:

<data name="a" />
<data name="b" />
<data name="c" />
<data name="SPLIT" />
<data name="d" />
<data name="e" />
<data name="SPLIT" />
<data name="f" />
<data name="g" />
<data name="h" />

Вывод должен выглядеть следующим образом

<div>
a
b
c
</div>

<div>
d
e
</div>

<div>
f
g
h
</div>

Я знаю, как сделать это путем «обмана», но хотел бы знать, есть ли правильный способ сделать это:

<div>
<xsl:for-each select="data">
    <xsl:choose>
    <xsl:when test="@name='SPLIT'">
        <xsl:text disable-output-escaping="yes"> &lt;/div&gt; &lt;div&gt;</xsl:text>
    </xsl:when>
    <xsl:otherwise>
        <xsl:value-of select="@name"/>
    </xsl:otherwise>
</xsl:for-each>
</div>

Ответы [ 2 ]

2 голосов
/ 27 октября 2010

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:template match="node()">
        <xsl:apply-templates 
                   select="node()[1]|following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="data">
        <div>
            <xsl:call-template name="open"/>
        </div>
        <xsl:apply-templates 
                   select="following-sibling::data[@name='SPLIT'][1]
                                    /following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="data" mode="open" name="open">
        <xsl:value-of select="concat(@name,'&#xA;')"/>
        <xsl:apply-templates select="following-sibling::node()[1]" 
                             mode="open"/>
    </xsl:template>
    <xsl:template match="data[@name='SPLIT']" mode="open"/>
</xsl:stylesheet>

Выход:

<div>
a
b
c
</div>
<div>
d
e
</div>
<div>
f
g
h
</div>

Примечание : Мелкозернистый обход.

2 голосов
/ 27 октября 2010

Это преобразование :

<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="data[not(@name='SPLIT')]"
 use="generate-id(preceding-sibling::data[@name='SPLIT'][1])"/>

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

 <xsl:template match="data[@name='SPLIT']" name="regularSplit">
  <div>
   <xsl:apply-templates mode="copy"
    select="key('kFollowing', generate-id())"/>
  </div>
 </xsl:template>

  <xsl:template match="data[@name='SPLIT'][
              not(preceding-sibling::data[@name='SPLIT'])]">
  <div>
   <xsl:apply-templates mode="copy"
    select="preceding-sibling::data"/>
  </div>
   <xsl:call-template name="regularSplit"/>
 </xsl:template>

 <xsl:template match="*" mode="copy">
  <xsl:call-template name="identity"/>
 </xsl:template>
<xsl:template match="data[not(@name='SPLIT')]"/>
</xsl:stylesheet>

при применении к предоставленному документу XML (обернутый в верхний элемент для формирования правильной формы):

<t>
    <data name="a" />
    <data name="b" />
    <data name="c" />
    <data name="SPLIT" />
    <data name="d" />
    <data name="e" />
    <data name="SPLIT" />
    <data name="f" />
    <data name="g" />
    <data name="h" />
</t>

дает желаемый, правильный результат :

<t>
    <div>
        <data name="a"></data>
        <data name="b"></data>
        <data name="c"></data>
    </div>
    <div>
        <data name="d"></data>
        <data name="e"></data>
    </div>
    <div>
        <data name="f"></data>
        <data name="g"></data>
        <data name="h"></data>
    </div>
</t>

Заметьте : ключи используются для удобного и эффективного определения всех элементов, не являющихся разделителями, которые следуют сразу за элементом "РАЗДЕЛИТЬ".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...