使用xslt创建xml(每页有delta的项目)

时间:2009-11-30 06:01:50

标签: xslt

我正在使用XSLT 1.0来转换一些XML文档。我有一个问题要做一件事,因为我需要一些帮助,请:

我的XML文档中有一组项目如下:

<item1>...</item1>  
<item2>...</item2>  
<!-- ... -->  
<itemN>...</itemN>

我想基于delta(每页项目数)创建类似这样的内容,例如delta为3:

<page>  
  <item1>...</item1>  
  <item2>...</item2>  
  <item3>...</item3>  
</page>  
<page>  
  <item4>...</item4>  
  <item5>...</item5>    
  <item6>...</item6>  
</page>

因此,基本上在XSLT中创建一个XML结构,每个页面都会放置固定数量的项目。

如果试过这样的事情(为了使用节点集):

<xsl:variable name="all_items_per_delta">  
  <xsl:for-each select="item">    
    <!-- if position is one or if mod of 3 then insert a page node, 
         so for first contract and for 3th, 6th, 9th... item -->
    <xsl:if test="position() = 1">  
      <page>  
    </xsl:if>  
    <!-- in the meantime for every contract insert the contract node -->
    <item>
      <!-- ... -->
    </item> 
    <!-- if position is one or if mod of 3 then insert a page node, 
         so for first item and for 3th, 6th, 9th... item--> 
    <xsl:if test="( (position() mod 3) = 0) ) and ( position() != last() )"> 
      </page>
      <page>
    </xsl:if>    
    <!-- if the position is last just end the page element -->
    <xsl:if test="position() = last()">  `  
      </page>
    </xsl:if>
  </xsl:for-each>
</xsl:variable>

但这不起作用,因为xslt解析器说

'Expected end of tag 'page' 

这是我要添加的第一个<page>标记。我似乎必须在同一行结束页面标签</page>。使用<xslt:if>时,它无法正常运行。

请指教,我如何制作这种树片段结构,以便以后使用EXSL扩展提取节点集。 谢谢。

3 个答案:

答案 0 :(得分:2)

它不起作用的原因是因为XSLT本身必须是格式良好的XML;例如这样:

<xsl:if test="...">
   </page>
</xsl:if>

不是格式良好的XML。简单地说,你不能在一个构造中包含一个开始标记,而在另一个构造中关闭一个。

现在关于如何正确处理这个问题。一种简单的方法是在外部循环中获取每个_n_th元素,并为其生成<page>元素;然后将该元素和以下 n -1元素放在<page>内:

<xsl:for-each select="item[position() mod $n = 0]">
   <page>
       <xsl:copy-of select=". | following-sibling::item[position() &lt; $n)]">
   </page>
</xsl:for-each>

或者,您可能希望使用Muenchean method,按position() mod $n对项目进行分组。

答案 1 :(得分:2)

我使用Pavel的答案,略有改动,用于分页:

<xsl:param name="itemsPerPage" select="10"/>

<xsl:for-each select="item[position() mod $itemsPerPage = 1 or position() = 1]">
  <page>
    <xsl:for-each select=". | following-sibling::item[position() &lt; $itemsPerPage]" >
    <!-- code to print out items -->
    </xsl:for-each>
  </page>
</xsl:for-each>

我认为你需要or position() = 1来包含列表中的第一项。另请注意mod $itemsPerPage = 1。例如,如果您希望每页有10个项目,则需要在第一个for-each循环中选择项目1,11,21等。

答案 2 :(得分:0)

这需要一种在XSLT中进行分组的方法。 XSLT 1.0提供的支持很少,它需要Munchean方法的天才来解决它。 XSLT 2.0支持更多(但并非所有环境,例如某些MS环境)都支持XSLT2.0。

一些资源(来自helpfule XML专家)是:

http://www.jenitennison.com/xslt/grouping/

http://www.dpawson.co.uk/xsl/sect2/N4486.html

http://www.xml.com/pub/a/2003/11/05/tr.html