2012-05-02 63 views
7

Tengo un documento XML con chapters y anidado sections. Estoy tratando de encontrar, para cualquier sección, el primer ancestro de la sección de segundo nivel. Esta es la penúltima sección del eje ancestor-or-self. pseudo-código:busque el penúltimo nodo con xpath

<chapter><title>mychapter</title> 
    <section><title>first</title> 
    <section><title>second</title> 
     <more/><stuff/> 
    </section> 
    </section> 
</chapter> 

mi selectora:

<xsl:apply-templates 
    select="ancestor-or-self::section[last()-1]" mode="title.markup" /> 

Por supuesto que funciona hasta el pasado() - 1 no está definido (el nodo actual es la sección first).

Si el nodo actual está por debajo de la sección second, quiero el título second. De lo contrario, quiero el título first.

+0

Votación a favor por el uso de DocBook. –

Respuesta

4

reemplazar su XPath con esto:

ancestor-or-self::section[position()=last()-1 or count(ancestor::section)=0][1] 

Desde ya se puede encontrar el nodo derecho en todos los casos excepto uno, he actualizado su XPath para también encontrar la sección first (or count(ancestor::section)=0) y, a continuación, seleccione ([1]) la primera coincidencia (en orden de documento inverso, ya que estamos utilizando el eje ancestor-or-self).

+0

Eso funciona, gracias. Después de probar su solución, pensé que podría simplificarlo con esto, pero desafortunadamente parece que siempre selecciona la sección actual. 'ancestro-o-auto :: d: sección [último() - 1 o último()] [1]' – Tim

+0

@Tim 'ancestro-o-auto :: sección [último() - booleano (ancestro :: sección) ] [1] ' –

+0

@Aleh, solución elegante! – Tim

2

Aquí es una solución más corto y más eficiente:

(ancestor-or-self::section[position() > last() -2])[last()] 

Esto selecciona el último de los dos primeros ancestros posiblemente más altas nombrados section. Si solo hay uno de esos antepasados, entonces es el último.

Aquí es una transformación completa:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="text"/> 

<xsl:template match="section"> 
    <xsl:value-of select="title"/> 
    <xsl:text> --> </xsl:text> 

    <xsl:value-of select= 
    "(ancestor-or-self::section[position() > last() -2])[last()]/title"/> 
    <xsl:text>&#xA;</xsl:text> 
    <xsl:apply-templates/> 
</xsl:template> 

<xsl:template match="text()"/> 
</xsl:stylesheet> 

Cuando se aplica esta transformación en el siguiente documento (basado en el proporcionado, pero añadió más anidados section elementos):

<chapter> 
    <title>mychapter</title> 
    <section> 
     <title>first</title> 
     <section> 
      <title>second</title> 
      <more/> 
      <stuff/> 
     <section> 
      <title>third</title> 
     </section> 
     </section> 
    </section> 
</chapter> 

se producen los resultados correctos:

first --> first 
second --> second 
third --> second 
Cuestiones relacionadas