2008-10-22 15 views
13

Encontré this page describiendo el método de Muenchian, pero creo que lo estoy aplicando mal.Cómo seleccionar nodos únicos

consideran que esta sería devolver un conjunto de edades:

/doc/class/person/descriptive[(@name='age')]/value 

1..2..2..2..3..3..4..7

Pero me gustaría un nodo solo un nodo para cada edad.

1..2..3..4..7

Cada uno de ellos parece que devolver todos los valores, en lugar de valores únicos:

/doc/class/person/descriptive[(@name='age')][not(value=preceding-sibling::value)]/value 
/doc/class/person/descriptive[(@name='age')]/value[not(value=preceding-sibling::value)] 

Qué am ¿Me pierdo?

+0

Vaya, parece que el ejemplo I seguido fue * no * el método de Muenchian, en cambio contra lo que el autor lo estaba contrastando. – pc1oad1etter

Respuesta

20

He aquí un ejemplo:

<root> 
    <item type='test'>A</item> 
    <item type='test'>B</item> 
    <item type='test'>C</item> 
    <item type='test'>A</item> 
    <item type='other'>A</item> 
    <item type='test'>B</item> 
    <item type='other'>D</item> 
    <item type=''>A</item> 
</root> 

Y el XPath:

//preceding::item/preceding::item[not(.=preceding-sibling::item)]/text() 

Resultados: ABCD

EDITAR: Como mousio comentó, esto no captura el último elemento en una lista si es la única vez que aparece. Tomando eso y comentario de Fëanor en cuenta, aquí hay una solución mejor:

/root/item[not(.=preceding-sibling::item)] 
+0

Obviamente, puede usar XPath adicional para restringir en función del atributo de tipo u otros datos en su archivo real. Lo tuve allí durante mi prueba rápida. –

+0

También tenga en cuenta que el "elemento" en XPath no es una palabra clave, es el nombre del elemento en el documento XML en el que están trabajando los ejes anteriores :: y anteriores-hermanos ::. –

+1

No creo que el uso de // sea útil dado que la estructura está dada, así que sabemos que todos los nodos de elementos, y solo los nodos de elementos, aparecen debajo del nodo raíz, esto es mejor: raíz/elemento [. ! = hermano anterior] – markmnl

1

¿No le falta una referencia a 'descriptivo' justo después del valor precedente? Algo como lo siguiente:

/doc/class/person/descriptive[(@name='age')][not(value=preceding-sibling::descriptive[@name='age']/value)]/value 

(no lo he probado)

14

Aquí está la versión Muenchian de la respuesta del BQ usando sus datos:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output indent="yes" method="text"/> 
    <xsl:key name="item-by-value" match="item" use="."/> 

    <xsl:template match="/"> 
    <xsl:apply-templates select="/root/item"/> 
    </xsl:template> 

    <xsl:template match="item"> 
    <xsl:if test="generate-id() = generate-id(key('item-by-value', normalize-space(.)))"> 
     <xsl:value-of select="."/> 
     <xsl:text> 
</xsl:text> 
    </xsl:if> 
    </xsl:template> 

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

Este transformar da

Un
B
C
D

  1. La búsqueda key() anterior en la plantilla para item devuelve un conjunto de nodos que contiene todos los elementos item con el mismo valor de cadena que el nodo de contexto.
  2. Si aplica una función que espera un nodo único a un conjunto de nodos, operará en el primer nodo en ese conjunto de nodos.
  3. Todas las llamadas a generate-id() están garantizadas para generar la misma ID para un nodo determinado durante una única pasada a través de un documento.
  4. Por lo tanto, la prueba será verdadera si el nodo de contexto es el mismo nodo que el primero devuelto por la llamada key().
+0

con un pequeño ajuste de los parámetros de coincidencia y uso esto funcionó como un amuleto dentro de un elemento para cada uno; ¡Gracias! –

+0

@ChuckB si un elemento elemento tiene un valor que contiene dos espacios, no se recoge (por ejemplo, A B). ¿Alguna idea de por qué es eso? –

+0

¿Cómo funciona 'position()' en este ejemplo? Digamos que comenzaste con un conjunto de nodos de 'A, A, A, B, B, B' y lo bajaste a' A, B', ¿habría alguna manera de obtener la nueva 'posición()' de 'A' y 'B', que debería ser' 1' para 'A' y' 2' para 'B'? – NessDan

2

El método Muenchian utiliza claves para crear una lista única de elementos del conjunto de nodos. Para los datos, la clave sería el siguiente:

<!-- Set the name to whatever you want --> 
<xsl:key name="PeopleAges" match="/doc/class/person/descriptive[@name = 'age']/value" use="." /> 

A partir de ahí, me gustaría utilizar personalmente xsl:apply-templates pero se puede utilizar la siguiente select atributo en otros lugares:

<!-- you can change `apply-templates` to: `copy-of` or `for-each`. --> 
<xsl:apply-templates select="/doc/class/person/descriptive[@name = 'age']/value[count(. | key('PeopleAges', .)[1]) = 1]" /> 

El partido de acompañamiento para la anterior es mucho más simple:

<xsl:template match="person/descriptive[@name = 'age']/value"> 
    <strong>Age: </strong><xsl:value-of select="." /> 
</xsl:template> 
3

para aquellos que todavía buscan un selecto distinto en XSLT:

Con XSLT 2.0, puede utilizar "valores distintos (/ doc/clase/persona/descriptiva [(@ name = 'edad')]/valor)"

Cuestiones relacionadas