对类似节点进行分组

时间:2010-10-04 07:46:58

标签: xslt-2.0

我在使用xsl:

对similer节点进行分组时遇到了以下问题

输入:

<?xml version="1.0" encoding="UTF-8"?>
<concept id="ads">
    <p>para1 content goes here</p>
    <Bullet>1</Bullet>
    <Bullet>2</Bullet>
    <Bullet>3</Bullet>
    <p>para2 content goes here</p>
    <Bullet>4</Bullet>
    <Bullet>5</Bullet>
    <p>para2 content goes here</p>
</concept>

输出应为:

<?xml version="1.0" encoding="UTF-8"?>
<concept id="ads">
    <p>para1 content goes here</p>
    <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    </ul>
    <p>para2 content goes here</p>
    <ul>
    <li>4</li>
    <li>5</li>
    </ul>
    <p>para2 content goes here</p>
</concept>

所有“子弹”元素都没有“兄弟”之前的兄弟姐妹,应该包含在“UL”和“Li”元素中。

我正在尝试这样的事情,但却无法实现结果:

<xsl:for-each select="Bullet[not(preceding-sibling::Bullet)]">
<ul>
<xsl:copy-of select="."/>
<xsl:variable name="current-name" select="generate-id(.)"/>
<xsl:for-each select="following-sibling::*[Bullet][generate-id(preceding-sibling::*[Bullet]) = $current-name]">
<xsl:copy-of select="."/>
</xsl:for-each>
</ul>
</xsl:for-each>

请帮忙。

---相关问题----

这在给定的xml输入上工作正常,但是 1.在我的实际xml中,这些<Bullet>标记可以出现在概念节点下的任何位置,因此使用<p>元素进行分组在这种情况下不起作用。

  1. 目前我正在处理除“子弹”节点以外的所有节点,因此我只需要匹配<Bullet>个具有紧随其后兄弟节点的节点<Bullet>并将序列包裹在{{} 1}}和<ul>中的每个<Bullet>。我当前的上下文节点是<li>

  2. 当前样式表如下:

                        

     应该在输入的同一位置呈现的节点.--&gt;
  3. 实际XML模式:

    <concept>

2 个答案:

答案 0 :(得分:1)

此样式表:

<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()[1]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="Bullet[preceding-sibling::node()[1]
                               [not(self::Bullet)]]">
        <ul>
            <xsl:call-template name="makeLi"/>
        </ul>
        <xsl:apply-templates select="following-sibling::node()
                                                     [not(self::Bullet)][1]"/>
    </xsl:template>
    <xsl:template match="Bullet" name="makeLi">
        <li>
            <xsl:value-of select="."/>
        </li>
        <xsl:apply-templates select="following-sibling::node()[1]
                                                              [self::Bullet]"/>
    </xsl:template>
</xsl:stylesheet>

编辑:只需将以下第一个“Bullet”规则更改为Bullet而不是p

输出(使用根元素包装您的输入以便正确形成):

<concept id="ads">
    <p>para1 content goes here</p>
    <Body-text>Body1 content goes here</Body-text>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
    <Body-text>Body2 content goes here</Body-text>
    <p>para2 content goes here</p>
    <ul>
        <li>4</li>
        <li>5</li>
    </ul>
    <p>para3 content goes here</p>
    <ul>
        <li>6</li>
        <li>7</li>
    </ul>
    <Body-text>Body2 content goes here</Body-text>
    <ul>
        <li>6</li>
        <li>7</li>
    </ul>
</concept>
<concept id="ads">
    <p>para1 content goes here</p>
    <Body-text>Body1 content goes here</Body-text>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
    <Body-text>Body2 content goes here</Body-text>
    <p>para2 content goes here</p>
    <ul>
        <li>4</li>
        <li>5</li>
    </ul>
    <p>para3 content goes here</p>
    <ul>
        <li>6</li>
        <li>7</li>
    </ul>
    <Body-text>Body2 content goes here</Body-text>
    <ul>
        <li>6</li>
        <li>7</li>
    </ul>
</concept>

注意:细粒度遍历。

使用分组,这个样式表:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="concept">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:for-each-group select="*" 
                                group-adjacent="boolean(self::Bullet)">
                <xsl:choose>
                    <xsl:when test="current-grouping-key()">
                        <ul>
                            <xsl:apply-templates select="current-group()"/>
                        </ul>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Bullet">
        <li>
            <xsl:value-of select="."/>
        </li>
    </xsl:template>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

编辑:使用group-adjacent

答案 1 :(得分:0)

此XSLT 2.0转换

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

    <xsl:template match="/*">
      <xsl:copy>
       <xsl:copy-of select="@*"/>
        <xsl:for-each-group select="*" group-starting-with="p">
          <xsl:copy-of select="current-group()[1]"/>
           <xsl:if test="current-group()[2]">
               <ul>
                <xsl:apply-templates select="current-group()[position() gt 1]"/>
              </ul>
          </xsl:if>
        </xsl:for-each-group>
      </xsl:copy>
    </xsl:template>

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

应用于提供的XML文档

<concept id="ads">
    <p>para1 content goes here</p>
    <Bullet>1</Bullet>
    <Bullet>2</Bullet>
    <Bullet>3</Bullet>
    <p>para2 content goes here</p>
    <Bullet>4</Bullet>
    <Bullet>5</Bullet>
    <p>para2 content goes here</p>
</concept>

生成想要的正确结果

<concept id="ads">
   <p>para1 content goes here</p>
   <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
   </ul>
   <p>para2 content goes here</p>
   <ul>
      <li>4</li>
      <li>5</li>
   </ul>
   <p>para2 content goes here</p>
</concept>

请注意<xsl:for-each-group>使用group-starting-with属性和current-group()功能。