2011-08-19 17 views
7

que tienen una estructura similar a la siguiente:Xpath: Seleccionar nodo pero no en elementos secundarios específicos

<page id='1'> 
    <title>Page 1</title>  
    <page id='2'> 
    <title>Sub Page 1</title> 
    </page> 
    <page id='3'> 
    <title>Sub Page 2</title> 
    </page>  
</page> 
<page id='4'> 
    <title>Page 2</title> 
</page> 

tengo que seleccionar una determinada página Id pero si esa página tiene páginas descendientes que no quieren volver esos elementos, pero yo quiero los otros elementos de esa página. Si selecciono Página 1 Quiero volver título, pero no las páginas hijas ...

//page[@id=1] 

Lo anterior me consigue la página 1, pero ¿Cómo excluir las páginas secundarias? Además, podría haber cualquier número arbitrario de elementos en una página.

//page[@id=1]/*[not(self::page)] 

He encontrado que esto me da los datos que quiero. Sin embargo, esos datos vuelven como una matriz de objetos con un objeto por elemento y aparentemente excluyen los nombres de los elementos ???. Estoy usando PHP SimpleXML por lo que vale.

+0

Buena pregunta, 1. Vea mi respuesta para una solución corta y simple. :) –

+1

"Sin embargo, esos datos vuelven como una matriz de objetos con un objeto por elemento". ¿Cómo es eso diferente de lo que quieres/necesitas? – LarsH

+0

Los datos vuelven en un formato diferente dependiendo de la consulta xpath, obtengo una matriz de SimpleXMLElement con una sola cadena en cada uno y me faltan los nombres de los elementos. El primer caso devuelve un único objeto SimpleXMLElement con todos los pares de valores clave esperados. No entiendo por qué, quizás abro otra pregunta. – Ben

Respuesta

7

Uso:

//page[@id=$yourId]/node()[not(self::page)] 

Esto selecciona todos los nodos que no son page y que son los niños de cualquier page en el documento, la valor de cadena cuyo atributo id es igual a la cadena contenida en $yourId (lo más probable es que sustituya $yourId anterior con un cadena específica deseada, como '1').

Aquí es un simple verificación basada en XSLT:

<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:param name="pId" select="3"/> 

<xsl:template match="/"> 
    <xsl:copy-of select="//page[@id=$pId]/node()[not(self::page)]"/> 
</xsl:template> 
</xsl:stylesheet> 

cuando se aplica esta transformación en el documento XML proporcionado (envuelto en un solo nodo superior para que sea bien formado):

<pages> 
    <page id='1'> 
     <title>Page 1</title> 
     <page id='2'> 
      <title>Sub Page 1</title> 
     </page> 
     <page id='3'> 
      <title>Sub Page 2</title> 
     </page> 
    </page> 
    <page id='4'> 
     <title>Page 2</title> 
    </page> 
</pages> 

el resultado deseado, adecuados, se produce:

<title>Sub Page 2</title> 

hacer la nota: Un supuesto hecho es que un valor id identifica de forma exclusiva un page. Si esto no es así, la expresión XPath propuesta seleccionará todos los elementospage cuyo atributo id tiene un valor de cadena de $yourId.

Si este es el caso y solo se debe seleccionar un elemento page, el OP debe especificar cuál de los muchos elementos page con este id debe seleccionarse.

Por ejemplo, puede ser el primero:

(//page[@id=$yourId]/node()[not(self::page)])[1] 

o el último:

(//page[@id=$yourId]/node()[not(self::page)])[last()] 

o ...

+0

Si bien esto se ve exactamente bien, en realidad no funciona ... No estoy seguro de si hay algún problema con xpath en el xml simple de PHP, pero esto devuelve varias copias de la página solicitada ??? – Ben

+0

@Ben: Esto puede suceder solo si más de una 'página' puede tener el mismo valor de su atributo 'id'. He actualizado mi respuesta para cubrir este caso. También proporciono una verificación simple que muestra que la expresión XPath inicial selecciona exactamente un elemento 'page' si un valor' id' identifica de manera única una 'página'. –

1

Si usted está interesado sólo en el elemento de título, esto funcionaría:

//page[@id=1]/title 

Sin embargo, si usted necesita otros sub-elementos de la página, no estoy seguro de XPath es la herramienta adecuada para usted. Suena más como algo para lo que un XSLT sería adecuado, ya que lo que realmente está haciendo es transformar sus datos.

+0

Lamentablemente necesito cualquier cantidad de elementos arbitrarios, excepto la página ... – Ben

+0

Respuesta actualizada con más información. Siéntase libre de votar si es útil de todos modos. :) –

+0

Gracias, estoy empezando a pensar que Xpath quizás no puede hacer esto. Siempre puedo escribir algo para procesar los datos que quiero, pero esperaba hacerlo a nivel de datos. – Ben

0

Si la página siempre tiene un título:

//page[@id='1']/*[not(boolean(./title))] 
Cuestiones relacionadas