Pergunta

I have an XML that goes like this:

<company>
    <employee name="john"/>
    <employee name="sarah"/>
    <employee name="kim"/>
    <employee name="karl"/>
    <employee name="tom"/>
    <employee name="jim"/>
    <employee name="sandy"/>
</company>

How can I use a XSLT template for selecting just the first n nodes, 3 for example, so I can get:

<company>
    <employee name="john"/>
    <employee name="sarah"/>
    <employee name="kim"/>
</company>

In Oxygen XML editor, I can use the following XPath to achieve that:

/company/employee[position() < (last() - count(/company/employee)+4)]

but I really need to use XSLT in this case
Thanks for your help

Foi útil?

Solução

How can I use a XSLT template for selecting just the first n nodes, 3 for example, so I can get:

<company> 
    <employee name="john"/> 
    <employee name="sarah"/> 
    <employee name="kim"/> 
</company>

The short answer: By knowing just a little bit XPath and XSLT.

Complete(but still short) answer:

This transformation:

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

 <xsl:template match="employee[position() > 3]"/>
</xsl:stylesheet>

when applied on the provided XML document:

<company>
    <employee name="john"/>
    <employee name="sarah"/>
    <employee name="kim"/>
    <employee name="karl"/>
    <employee name="tom"/>
    <employee name="jim"/>
    <employee name="sandy"/>
</company>

produces the wanted, correct result:

<company>
   <employee name="john"/>
   <employee name="sarah"/>
   <employee name="kim"/>
</company>

Do note:

  1. The identity rule is used to copy every node "as-is".

  2. There is just one specific template overriding the identity template. It matches any employee element with position in the node-list greater than 3. This template has an empty body, effectively discarding the matched elements.

Outras dicas

I can use the following XPath to achieve that:

/company/employee[position() < (last() - count(/company/employee)+4)]

Do note that here last() is equal to count(/company/employee), so this will be reduce to:

/company/employee[4 > position()]

In a pattern you could have:

<xsl:template match="employee[4 > position()]">    
...
</xsl:template>

The same with parametrization (Remenber you can't use parameter reference in XSLT 1.0 patterns):

<xsl:param name="pTop" select="3"/>    

<xsl:template match="employee">    
   <xsl:if test="$pTop >= position()">    
   ...
   </xsl:if>
</xsl:template>

Try this:

<xsl:for-each select="company/employee[position() &lt; 3]">
  ...
</xsl:for-each>

This might work with <template select=.... too but i'm not sure.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top